Skip to content

Commit 6c2b397

Browse files
committed
update analytics for api usage
1 parent a96bd34 commit 6c2b397

2 files changed

Lines changed: 64 additions & 85 deletions

File tree

api-docs.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,65 @@ curl -X GET "http://localhost:3432/api/db/model-performance?recalculate=true" \
12631263

12641264
---
12651265

1266+
### Analytics
1267+
1268+
#### GET `/api/analytics`
1269+
Get model analytics for the user (stats + insights).
1270+
1271+
**Authentication**: Session or API Key
1272+
1273+
**Query Parameters**:
1274+
- `recalculate`: Set to `"false"` to use cached stats. Defaults to `"true"`.
1275+
1276+
**Response**:
1277+
```json
1278+
{
1279+
"success": true,
1280+
"stats": [
1281+
{
1282+
"id": "string",
1283+
"modelId": "string",
1284+
"provider": "string",
1285+
"totalMessages": "number",
1286+
"avgRating": "number | null",
1287+
"thumbsUpCount": "number",
1288+
"thumbsDownCount": "number",
1289+
"regenerateCount": "number",
1290+
"avgResponseTime": "number | null",
1291+
"avgTokens": "number | null",
1292+
"totalCost": "number",
1293+
"errorCount": "number",
1294+
"accurateCount": "number",
1295+
"helpfulCount": "number",
1296+
"creativeCount": "number",
1297+
"fastCount": "number",
1298+
"costEffectiveCount": "number"
1299+
}
1300+
],
1301+
"insights": {
1302+
"totalMessages": "number",
1303+
"totalCost": "number",
1304+
"avgRating": "number | null",
1305+
"mostUsedModel": "ModelPerformanceStat | null",
1306+
"bestRatedModel": "ModelPerformanceStat | null",
1307+
"mostCostEffective": "ModelPerformanceStat | null",
1308+
"fastestModel": "ModelPerformanceStat | null"
1309+
}
1310+
}
1311+
```
1312+
1313+
**CURL Example**:
1314+
```bash
1315+
curl -X GET "http://localhost:3432/api/analytics" \
1316+
-b "session_cookie=your_session"
1317+
1318+
# Use cached stats
1319+
curl -X GET "http://localhost:3432/api/analytics?recalculate=false" \
1320+
-b "session_cookie=your_session"
1321+
```
1322+
1323+
---
1324+
12661325
### User Settings
12671326

12681327
#### GET `/api/db/user-settings`

src/routes/account/analytics/+page.server.ts

Lines changed: 5 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { redirect } from '@sveltejs/kit';
22
import type { PageServerLoad } from './$types';
33
import { auth } from '$lib/auth';
4-
import {
5-
getModelPerformanceStatsByUser,
6-
calculateAllModelPerformanceStats,
7-
} from '$lib/db/queries/model-performance';
4+
import { getModelAnalytics } from '$lib/analytics/model-analytics';
85

96
export const load: PageServerLoad = async ({ request }) => {
107
const session = await auth.api.getSession({ headers: request.headers });
@@ -18,91 +15,13 @@ export const load: PageServerLoad = async ({ request }) => {
1815
try {
1916
console.log(`[analytics] Loading analytics for user ${userId}`);
2017

21-
// Always recalculate stats to ensure they're up-to-date
22-
const stats = await calculateAllModelPerformanceStats(userId);
18+
const { stats, insights } = await getModelAnalytics(userId, { recalculate: true });
2319
console.log(`[analytics] Calculated stats for ${stats.length} models`);
24-
25-
// Calculate additional insights
26-
const totalMessages = stats.reduce((sum, s) => sum + s.totalMessages, 0);
27-
const totalCost = stats.reduce((sum, s) => {
28-
const cost = s.totalCost;
29-
if (cost === null || cost === undefined || isNaN(cost)) {
30-
return sum;
31-
}
32-
return sum + cost;
33-
}, 0);
34-
const avgRating =
35-
stats.filter((s) => s.avgRating !== null).length > 0
36-
? stats.reduce((sum, s) => sum + (s.avgRating ?? 0), 0) /
37-
stats.filter((s) => s.avgRating !== null).length
38-
: null;
39-
40-
// Find most used model
41-
const mostUsedModel =
42-
stats.length > 0
43-
? stats.reduce(
44-
(prev, current) => (current.totalMessages > prev.totalMessages ? current : prev),
45-
stats[0]!
46-
)
47-
: null;
48-
49-
// Find best rated model (with at least 5 messages)
50-
const qualifiedModels = stats.filter((s) => s.totalMessages >= 5 && s.avgRating !== null);
51-
const bestRatedModel =
52-
qualifiedModels.length > 0
53-
? qualifiedModels.reduce((prev, current) =>
54-
(current.avgRating ?? 0) > (prev.avgRating ?? 0) ? current : prev
55-
)
56-
: null;
57-
58-
// Find most cost-effective model (lowest cost per message with at least 5 messages)
59-
const modelsWithCost = stats.filter((s) => s.totalMessages >= 5 && s.totalCost > 0);
60-
const mostCostEffective =
61-
modelsWithCost.length > 0
62-
? modelsWithCost.reduce((prev, current) => {
63-
const prevCostPerMsg = prev.totalCost / prev.totalMessages;
64-
const currentCostPerMsg = current.totalCost / current.totalMessages;
65-
return currentCostPerMsg < prevCostPerMsg ? current : prev;
66-
})
67-
: null;
68-
69-
// Find fastest model by tokens/sec (requires avgTokens and avgResponseTime with at least 5 messages)
70-
const modelsWithSpeed = stats.filter(
71-
(s) =>
72-
s.totalMessages >= 5 &&
73-
s.avgTokens !== null &&
74-
s.avgTokens !== undefined &&
75-
s.avgResponseTime !== null &&
76-
s.avgResponseTime !== undefined &&
77-
s.avgResponseTime > 0
78-
);
79-
80-
const fastestModel =
81-
modelsWithSpeed.length > 0
82-
? modelsWithSpeed.reduce((prev, current) => {
83-
const prevSpeed = (prev.avgTokens ?? 0) / ((prev.avgResponseTime ?? 0) / 1000 || 1); // tokens per second
84-
const currentSpeed =
85-
(current.avgTokens ?? 0) / ((current.avgResponseTime ?? 0) / 1000 || 1);
86-
return currentSpeed > prevSpeed ? current : prev;
87-
})
88-
: null;
89-
9020
console.log(
91-
`[analytics] Generated insights: ${totalMessages} messages, $${totalCost.toFixed(2)} cost`
21+
`[analytics] Generated insights: ${insights.totalMessages} messages, $${insights.totalCost.toFixed(2)} cost`
9222
);
9323

94-
return {
95-
stats,
96-
insights: {
97-
totalMessages,
98-
totalCost,
99-
avgRating,
100-
mostUsedModel,
101-
bestRatedModel,
102-
mostCostEffective,
103-
fastestModel,
104-
},
105-
};
24+
return { stats, insights };
10625
} catch (err) {
10726
console.error(`[analytics] Error loading analytics for user ${userId}:`, err);
10827
// Return empty data on error rather than crashing
@@ -115,6 +34,7 @@ export const load: PageServerLoad = async ({ request }) => {
11534
mostUsedModel: null,
11635
bestRatedModel: null,
11736
mostCostEffective: null,
37+
fastestModel: null,
11838
},
11939
};
12040
}

0 commit comments

Comments
 (0)