Skip to content

Commit 3cfe4cb

Browse files
committed
Replace Available Months from Metadata plugin to Monthly Analytics API
1 parent 0a60981 commit 3cfe4cb

File tree

10 files changed

+50
-87
lines changed

10 files changed

+50
-87
lines changed

ServiceStack/src/ServiceStack.AI.Chat/AdminChatServices.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class AdminMonthlyChatCompletionAnalytics : IGet, IReturn<AdminMonthlyCha
1818
public class AdminMonthlyChatCompletionAnalyticsResponse
1919
{
2020
public string Month { get; set; }
21+
public List<string> AvailableMonths { get; set; }
2122
public List<ChatCompletionStat> ModelStats { get; set; }
2223
public List<ChatCompletionStat> ProviderStats { get; set; }
2324
public List<ChatCompletionStat> DailyStats { get; set; }
@@ -55,6 +56,23 @@ public class AdminChatServices(IAutoQueryDb autoQuery)
5556
return (feature, chatStore);
5657
}
5758

59+
public static List<string> AvailableMonths { get; set; } = [];
60+
61+
public List<string> GetAvailableMonths(IChatStore chatStore)
62+
{
63+
using var db = chatStore.OpenDb();
64+
var currentMonth = DateTime.UtcNow.ToString("yyyy-MM");
65+
if (AvailableMonths.Count == 0 || !AvailableMonths.Contains(currentMonth))
66+
{
67+
var months = chatStore.GetAvailableMonths(db)
68+
.Map(x => x.ToString("yyyy-MM"));
69+
if (months.Count == 0)
70+
months.Add(currentMonth);
71+
AvailableMonths = months;
72+
}
73+
return AvailableMonths;
74+
}
75+
5876
public async Task<object> Any(AdminQueryChatCompletionLogs request)
5977
{
6078
var (feature, chatStore) = AssertRequiredRole();
@@ -107,8 +125,11 @@ public async Task<object> Any(AdminMonthlyChatCompletionAnalytics request)
107125
Cost = Sql.Sum(x.Cost),
108126
}));
109127

128+
var availableMonths = GetAvailableMonths(chatStore);
129+
110130
return new AdminMonthlyChatCompletionAnalyticsResponse
111131
{
132+
AvailableMonths = availableMonths,
112133
Month = month.ToString("yyyy-MM"),
113134
ModelStats = modelStats,
114135
ProviderStats = providerStats,

ServiceStack/src/ServiceStack.AI.Chat/ChatFeature.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -174,20 +174,6 @@ public void Register(IAppHost appHost)
174174
{
175175
ChatStore.InitSchema();
176176
}
177-
178-
using var db = ChatStore.OpenDb();
179-
var months = ChatStore.GetAvailableMonths(db)
180-
.Map(x => x.ToString("yyyy-MM"));
181-
182-
appHost.AddToAppMetadata(meta => {
183-
meta.Plugins.AdminChat = new AdminChatInfo {
184-
AccessRole = RoleNames.Admin,
185-
DefaultLimit = DefaultLimit,
186-
Analytics = new AiChatAnalytics {
187-
Months = months,
188-
}
189-
};
190-
});
191177
}
192178
}
193179

ServiceStack/src/ServiceStack.AI.Chat/DbChatStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class DbChatStore(ILogger<DbChatStore> log, IDbConnectionFactory dbFactor
1717
public Action<IDbConnection> Configure { get; set; } = DefaultConfigureDb;
1818
public static void DefaultConfigureDb(IDbConnection db) => db.WithTag(nameof(DbChatStore));
1919
public IDbConnection OpenDb() => NamedConnection != null
20-
? dbFactory.Open(NamedConnection)
20+
? dbFactory.Open(NamedConnection, Configure)
2121
: dbFactory.Open(Configure);
2222

2323
public IDbConnection OpenMonthDb(DateTime? month=null) => OpenDb();

ServiceStack/src/ServiceStack.AI.Chat/PostgresChatStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class PostgresChatStore(ILogger<PostgresChatStore> log, IDbConnectionFact
1717
public Action<IDbConnection> Configure { get; set; } = DefaultConfigureDb;
1818
public static void DefaultConfigureDb(IDbConnection db) => db.WithTag(nameof(DbChatStore));
1919
public IDbConnection OpenDb() => NamedConnection != null
20-
? dbFactory.Open(NamedConnection)
20+
? dbFactory.Open(NamedConnection, Configure)
2121
: dbFactory.Open(Configure);
2222

2323
public IDbConnection OpenMonthDb(DateTime? month=null)

ServiceStack/src/ServiceStack.AI.Chat/modules/admin-ui/components/AdminChat.mjs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,12 @@ export class AdminMonthlyChatCompletionAnalytics {
8282
createResponse() { return new AdminMonthlyChatCompletionAnalyticsResponse() }
8383
}
8484
export class AdminMonthlyChatCompletionAnalyticsResponse {
85-
/** @param {{month?:string,modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
85+
/** @param {{month?:string,availableMonths?:string[],modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
8686
constructor(init) { Object.assign(this, init) }
8787
/** @type {string} */
8888
month;
89+
/** @type {string[]} */
90+
availableMonths = [];
8991
/** @type {ChatCompletionStat[]} */
9092
modelStats = [];
9193
/** @type {ChatCompletionStat[]} */
@@ -501,7 +503,7 @@ export const AdminChat = {
501503
</div>
502504
503505
<!-- Daily Breakdown Pie Charts -->
504-
<div v-if="selectedDay && dailyAnalytics">
506+
<div v-if="selectedDay && dailyAnalytics && (dailyAnalytics.modelStats || []).reduce((sum, s) => sum + (s.requests || 0), 0) > 0">
505507
<!-- Title with Date and Stats -->
506508
<div class="p-3 mb-3">
507509
<div class="flex items-center justify-between">
@@ -574,7 +576,7 @@ export const AdminChat = {
574576
</div>
575577
576578
<!-- Daily Breakdown Pie Charts -->
577-
<div v-if="selectedDay && dailyAnalytics">
579+
<div v-if="selectedDay && dailyAnalytics && (dailyAnalytics.modelStats || []).reduce((sum, s) => sum + (s.requests || 0), 0) > 0">
578580
<!-- Title with Date and Stats -->
579581
<div class="p-3 mb-3">
580582
<div class="flex items-center justify-between">
@@ -786,8 +788,8 @@ export const AdminChat = {
786788
// Data refs
787789
const analytics = ref(null)
788790
const dailyAnalytics = ref(null)
791+
const months = computed(() => analytics.value?.availableMonths ?? [])
789792
const logs = ref([])
790-
const months = ref(server.plugins.adminChat?.analytics?.months ?? [])
791793
const sortBy = ref('-id')
792794
const currentPage = ref(1)
793795
const pageSize = ref(25)

ServiceStack/src/ServiceStack.Client/MetadataTypes.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ public class PluginInfo : IMeta
163163
public AdminIdentityUsersInfo AdminIdentityUsers { get; set; }
164164
public AdminRedisInfo AdminRedis { get; set; }
165165
public AdminDatabaseInfo AdminDatabase { get; set; }
166-
public AdminChatInfo AdminChat { get; set; }
167166
public Dictionary<string, string> Meta { get; set; }
168167
}
169168

@@ -423,21 +422,6 @@ public class SchemaInfo
423422
public List<string> Tables { get; set; }
424423
}
425424

426-
427-
[Exclude(Feature.Soap | Feature.ApiExplorer)]
428-
public class AdminChatInfo : IMeta
429-
{
430-
public string AccessRole { get; set; }
431-
public int DefaultLimit { get; set; }
432-
public AiChatAnalytics Analytics { get; set; }
433-
public Dictionary<string, string> Meta { get; set; }
434-
}
435-
public class AiChatAnalytics
436-
{
437-
public List<string> Months { get; set; }
438-
}
439-
440-
441425
[Exclude(Feature.Soap | Feature.ApiExplorer)]
442426
public class ApiKeyInfo : IMeta
443427
{

ServiceStack/src/ServiceStack/modules/admin-ui/lib/dtos.mjs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Options:
2-
Date: 2025-11-05 18:02:25
2+
Date: 2025-11-06 11:47:32
33
Version: 8.91
44
Tip: To override a DTO option, remove "//" prefix before updating
55
BaseUrl: http://localhost:20000
@@ -1375,26 +1375,8 @@ export class AdminDatabaseInfo {
13751375
/** @type {{ [index:string]: string; }} */
13761376
meta;
13771377
}
1378-
export class AiChatAnalytics {
1379-
/** @param {{months?:string[]}} [init] */
1380-
constructor(init) { Object.assign(this, init) }
1381-
/** @type {string[]} */
1382-
months;
1383-
}
1384-
export class AdminChatInfo {
1385-
/** @param {{accessRole?:string,defaultLimit?:number,analytics?:AiChatAnalytics,meta?:{ [index:string]: string; }}} [init] */
1386-
constructor(init) { Object.assign(this, init) }
1387-
/** @type {string} */
1388-
accessRole;
1389-
/** @type {number} */
1390-
defaultLimit;
1391-
/** @type {AiChatAnalytics} */
1392-
analytics;
1393-
/** @type {{ [index:string]: string; }} */
1394-
meta;
1395-
}
13961378
export class PluginInfo {
1397-
/** @param {{loaded?:string[],auth?:AuthInfo,apiKey?:ApiKeyInfo,commands?:CommandsInfo,autoQuery?:AutoQueryInfo,validation?:ValidationInfo,sharpPages?:SharpPagesInfo,requestLogs?:RequestLogsInfo,profiling?:ProfilingInfo,filesUpload?:FilesUploadInfo,adminUsers?:AdminUsersInfo,adminIdentityUsers?:AdminIdentityUsersInfo,adminRedis?:AdminRedisInfo,adminDatabase?:AdminDatabaseInfo,adminChat?:AdminChatInfo,meta?:{ [index:string]: string; }}} [init] */
1379+
/** @param {{loaded?:string[],auth?:AuthInfo,apiKey?:ApiKeyInfo,commands?:CommandsInfo,autoQuery?:AutoQueryInfo,validation?:ValidationInfo,sharpPages?:SharpPagesInfo,requestLogs?:RequestLogsInfo,profiling?:ProfilingInfo,filesUpload?:FilesUploadInfo,adminUsers?:AdminUsersInfo,adminIdentityUsers?:AdminIdentityUsersInfo,adminRedis?:AdminRedisInfo,adminDatabase?:AdminDatabaseInfo,meta?:{ [index:string]: string; }}} [init] */
13981380
constructor(init) { Object.assign(this, init) }
13991381
/** @type {string[]} */
14001382
loaded;
@@ -1424,8 +1406,6 @@ export class PluginInfo {
14241406
adminRedis;
14251407
/** @type {AdminDatabaseInfo} */
14261408
adminDatabase;
1427-
/** @type {AdminChatInfo} */
1428-
adminChat;
14291409
/** @type {{ [index:string]: string; }} */
14301410
meta;
14311411
}
@@ -2366,10 +2346,12 @@ export class ChatResponse {
23662346
responseStatus;
23672347
}
23682348
export class AdminMonthlyChatCompletionAnalyticsResponse {
2369-
/** @param {{month?:string,modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
2349+
/** @param {{month?:string,availableMonths?:string[],modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
23702350
constructor(init) { Object.assign(this, init) }
23712351
/** @type {string} */
23722352
month;
2353+
/** @type {string[]} */
2354+
availableMonths = [];
23732355
/** @type {ChatCompletionStat[]} */
23742356
modelStats = [];
23752357
/** @type {ChatCompletionStat[]} */

ServiceStack/tests/AdhocNew/Configure.AI.Chat.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ public void Configure(IWebHostBuilder builder) => builder
1616
// ValidateRequest = async (req) => req.GetApiKey()?.HasScope(RoleNames.Admin) == true
1717
// ? null
1818
// : HttpResult.Redirect("/admin-ui"),
19+
Variables = {
20+
["GOOGLE_API_KEY"] = Environment.GetEnvironmentVariable("GOOGLE_FREE_API_KEY")!
21+
}
1922
});
20-
services.AddSingleton<IChatStore,PostgresChatStore>();
23+
// services.AddSingleton<IChatStore,PostgresChatStore>();
24+
services.AddSingleton<IChatStore,DbChatStore>();
2125

2226
services.ConfigurePlugin<MetadataFeature>(feature => {
2327
feature.AddPluginLink("/chat", "AI Chat");

ServiceStack/tests/NorthwindAuto/admin-ui/components/AdminChat.mjs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,12 @@ export class AdminMonthlyChatCompletionAnalytics {
8282
createResponse() { return new AdminMonthlyChatCompletionAnalyticsResponse() }
8383
}
8484
export class AdminMonthlyChatCompletionAnalyticsResponse {
85-
/** @param {{month?:string,modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
85+
/** @param {{month?:string,availableMonths?:string[],modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
8686
constructor(init) { Object.assign(this, init) }
8787
/** @type {string} */
8888
month;
89+
/** @type {string[]} */
90+
availableMonths = [];
8991
/** @type {ChatCompletionStat[]} */
9092
modelStats = [];
9193
/** @type {ChatCompletionStat[]} */
@@ -501,7 +503,7 @@ export const AdminChat = {
501503
</div>
502504
503505
<!-- Daily Breakdown Pie Charts -->
504-
<div v-if="selectedDay && dailyAnalytics">
506+
<div v-if="selectedDay && dailyAnalytics && (dailyAnalytics.modelStats || []).reduce((sum, s) => sum + (s.requests || 0), 0) > 0">
505507
<!-- Title with Date and Stats -->
506508
<div class="p-3 mb-3">
507509
<div class="flex items-center justify-between">
@@ -574,7 +576,7 @@ export const AdminChat = {
574576
</div>
575577
576578
<!-- Daily Breakdown Pie Charts -->
577-
<div v-if="selectedDay && dailyAnalytics">
579+
<div v-if="selectedDay && dailyAnalytics && (dailyAnalytics.modelStats || []).reduce((sum, s) => sum + (s.requests || 0), 0) > 0">
578580
<!-- Title with Date and Stats -->
579581
<div class="p-3 mb-3">
580582
<div class="flex items-center justify-between">
@@ -786,8 +788,8 @@ export const AdminChat = {
786788
// Data refs
787789
const analytics = ref(null)
788790
const dailyAnalytics = ref(null)
791+
const months = computed(() => analytics.value?.availableMonths ?? [])
789792
const logs = ref([])
790-
const months = ref(server.plugins.adminChat?.analytics?.months ?? [])
791793
const sortBy = ref('-id')
792794
const currentPage = ref(1)
793795
const pageSize = ref(25)

ServiceStack/tests/NorthwindAuto/admin-ui/lib/dtos.mjs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Options:
2-
Date: 2025-11-05 18:02:25
2+
Date: 2025-11-06 11:47:32
33
Version: 8.91
44
Tip: To override a DTO option, remove "//" prefix before updating
55
BaseUrl: http://localhost:20000
@@ -1377,26 +1377,8 @@ export class AdminDatabaseInfo {
13771377
/** @type {{ [index:string]: string; }} */
13781378
meta;
13791379
}
1380-
export class AiChatAnalytics {
1381-
/** @param {{months?:string[]}} [init] */
1382-
constructor(init) { Object.assign(this, init) }
1383-
/** @type {string[]} */
1384-
months;
1385-
}
1386-
export class AdminChatInfo {
1387-
/** @param {{accessRole?:string,defaultLimit?:number,analytics?:AiChatAnalytics,meta?:{ [index:string]: string; }}} [init] */
1388-
constructor(init) { Object.assign(this, init) }
1389-
/** @type {string} */
1390-
accessRole;
1391-
/** @type {number} */
1392-
defaultLimit;
1393-
/** @type {AiChatAnalytics} */
1394-
analytics;
1395-
/** @type {{ [index:string]: string; }} */
1396-
meta;
1397-
}
13981380
export class PluginInfo {
1399-
/** @param {{loaded?:string[],auth?:AuthInfo,apiKey?:ApiKeyInfo,commands?:CommandsInfo,autoQuery?:AutoQueryInfo,validation?:ValidationInfo,sharpPages?:SharpPagesInfo,requestLogs?:RequestLogsInfo,profiling?:ProfilingInfo,filesUpload?:FilesUploadInfo,adminUsers?:AdminUsersInfo,adminIdentityUsers?:AdminIdentityUsersInfo,adminRedis?:AdminRedisInfo,adminDatabase?:AdminDatabaseInfo,adminChat?:AdminChatInfo,meta?:{ [index:string]: string; }}} [init] */
1381+
/** @param {{loaded?:string[],auth?:AuthInfo,apiKey?:ApiKeyInfo,commands?:CommandsInfo,autoQuery?:AutoQueryInfo,validation?:ValidationInfo,sharpPages?:SharpPagesInfo,requestLogs?:RequestLogsInfo,profiling?:ProfilingInfo,filesUpload?:FilesUploadInfo,adminUsers?:AdminUsersInfo,adminIdentityUsers?:AdminIdentityUsersInfo,adminRedis?:AdminRedisInfo,adminDatabase?:AdminDatabaseInfo,meta?:{ [index:string]: string; }}} [init] */
14001382
constructor(init) { Object.assign(this, init) }
14011383
/** @type {string[]} */
14021384
loaded;
@@ -1426,8 +1408,6 @@ export class PluginInfo {
14261408
adminRedis;
14271409
/** @type {AdminDatabaseInfo} */
14281410
adminDatabase;
1429-
/** @type {AdminChatInfo} */
1430-
adminChat;
14311411
/** @type {{ [index:string]: string; }} */
14321412
meta;
14331413
}
@@ -2370,10 +2350,12 @@ export class ChatResponse {
23702350
responseStatus;
23712351
}
23722352
export class AdminMonthlyChatCompletionAnalyticsResponse {
2373-
/** @param {{month?:string,modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
2353+
/** @param {{month?:string,availableMonths?:string[],modelStats?:ChatCompletionStat[],providerStats?:ChatCompletionStat[],dailyStats?:ChatCompletionStat[]}} [init] */
23742354
constructor(init) { Object.assign(this, init) }
23752355
/** @type {string} */
23762356
month;
2357+
/** @type {string[]} */
2358+
availableMonths = [];
23772359
/** @type {ChatCompletionStat[]} */
23782360
modelStats = [];
23792361
/** @type {ChatCompletionStat[]} */

0 commit comments

Comments
 (0)