Skip to content

Commit 1104844

Browse files
authored
Merge pull request #137 from zhujunsan/kerwin_main
feat: 增加用户使用量统计页面
2 parents f3f9fe7 + 604755a commit 1104844

File tree

13 files changed

+369
-9
lines changed

13 files changed

+369
-9
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"dependencies": {
2626
"@traptitech/markdown-it-katex": "^3.6.0",
2727
"@vueuse/core": "^9.13.0",
28+
"chart.js": "^4.3.0",
29+
"dayjs": "^1.11.7",
2830
"highlight.js": "^11.7.0",
2931
"html2canvas": "^1.4.1",
3032
"jwt-decode": "^3.1.2",
@@ -33,6 +35,7 @@
3335
"naive-ui": "^2.34.3",
3436
"pinia": "^2.0.33",
3537
"vue": "^3.2.47",
38+
"vue-chartjs": "^5.2.0",
3639
"vue-i18n": "^9.2.2",
3740
"vue-router": "^4.1.6"
3841
},
@@ -41,6 +44,7 @@
4144
"@commitlint/cli": "^17.4.4",
4245
"@commitlint/config-conventional": "^17.4.4",
4346
"@iconify/vue": "^4.1.0",
47+
"@types/chart.js": "^2.9.37",
4448
"@types/crypto-js": "^4.1.1",
4549
"@types/katex": "^0.16.0",
4650
"@types/markdown-it": "^12.2.3",

pnpm-lock.yaml

Lines changed: 56 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"dependencies": {
2727
"axios": "^1.3.4",
2828
"chatgpt": "^5.2.4",
29+
"dayjs": "^1.11.7",
2930
"dotenv": "^16.0.3",
3031
"esno": "^0.16.3",
3132
"express": "^4.18.2",

service/pnpm-lock.yaml

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/src/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
getChats,
2424
getUser,
2525
getUserById,
26+
getUserStatisticsByDay,
2627
insertChat,
2728
insertChatUsage,
2829
renameChatRoom,
@@ -716,6 +717,19 @@ router.post('/audit-test', rootAuth, async (req, res) => {
716717
}
717718
})
718719

720+
router.post('/statistics/by-day', auth, async (req, res) => {
721+
try {
722+
const userId = req.headers.userId
723+
const { start, end } = req.body as { start: number; end: number }
724+
725+
const data = await getUserStatisticsByDay(new ObjectId(userId as string), start, end)
726+
res.send({ status: 'Success', message: '', data })
727+
}
728+
catch (error) {
729+
res.send(error)
730+
}
731+
})
732+
719733
app.use('', router)
720734
app.use('/api', router)
721735
app.set('trust proxy', 1)

service/src/storage/mongo.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MongoClient, ObjectId } from 'mongodb'
22
import * as dotenv from 'dotenv'
3+
import dayjs from 'dayjs'
34
import { ChatInfo, ChatRoom, ChatUsage, Status, UserInfo } from './model'
45
import type { ChatOptions, Config, UsageResponse } from './model'
56

@@ -211,3 +212,72 @@ export async function updateConfig(config: Config): Promise<Config> {
211212
return config
212213
return null
213214
}
215+
216+
export async function getUserStatisticsByDay(userId: ObjectId, start: number, end: number): Promise<any> {
217+
const pipeline = [
218+
{ // filter by dateTime
219+
$match: {
220+
dateTime: {
221+
$gte: start,
222+
$lte: end,
223+
},
224+
userId,
225+
},
226+
},
227+
{ // convert dateTime to date
228+
$addFields: {
229+
date: {
230+
$dateToString: {
231+
format: '%Y-%m-%d',
232+
date: {
233+
$toDate: '$dateTime',
234+
},
235+
},
236+
},
237+
},
238+
},
239+
{ // group by date
240+
$group: {
241+
_id: '$date',
242+
promptTokens: {
243+
$sum: '$promptTokens',
244+
},
245+
completionTokens: {
246+
$sum: '$completionTokens',
247+
},
248+
totalTokens: {
249+
$sum: '$totalTokens',
250+
},
251+
},
252+
},
253+
{ // sort by date
254+
$sort: {
255+
_id: 1,
256+
},
257+
},
258+
]
259+
260+
const aggStatics = await usageCol.aggregate(pipeline).toArray()
261+
262+
const step = 86400000 // 1 day in milliseconds
263+
const result = {
264+
promptTokens: null,
265+
completionTokens: null,
266+
totalTokens: null,
267+
chartData: [],
268+
}
269+
for (let i = start; i <= end; i += step) {
270+
// Convert the timestamp to a Date object
271+
const date = dayjs(i, 'x').format('YYYY-MM-DD')
272+
273+
const dateData = aggStatics.find(x => x._id === date)
274+
|| { _id: date, promptTokens: 0, completionTokens: 0, totalTokens: 0 }
275+
276+
result.promptTokens += dateData.promptTokens
277+
result.completionTokens += dateData.completionTokens
278+
result.totalTokens += dateData.totalTokens
279+
result.chartData.push(dateData)
280+
}
281+
282+
return result
283+
}

src/api/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,10 @@ export function fetchUpdateBaseSetting<T = any>(config: ConfigState) {
216216
data: config,
217217
})
218218
}
219+
220+
export function fetchUserStatistics<T = any>(start: number, end: number) {
221+
return post<T>({
222+
url: '/statistics/by-day',
223+
data: { start, end },
224+
})
225+
}

0 commit comments

Comments
 (0)