@gehennawu/dsh-service 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/client.js +55 -18
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -38,7 +38,7 @@ The plugin also appears under **Plugins → Plugin configuration**, with six hos
|
|
|
38
38
|
|
|
39
39
|
- 7-day stacked bar chart of input/output/cache tokens with blue/orange/teal legend
|
|
40
40
|
- Filter by project; hover for exact values
|
|
41
|
-
- Model breakdown as horizontal stacked bars (same legend colors),
|
|
41
|
+
- Model breakdown as horizontal stacked bars (same legend colors) with a "Today / Last 7 days / All time" toggle on the right of the list header (default: last 7 days): Today aggregates only the current day, Last 7 days ranks within the chart's window, and All time covers every date in the index (bounded by session retention); each row keeps `x times · Cache hit x% · Input xM token · Output xM token`
|
|
42
42
|
- Steps whose provider reports no token usage are excluded from the statistics
|
|
43
43
|
- Last-24-hour model/tool error statistics, collapsed by default
|
|
44
44
|
|
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
- 近 7 天输入/输出/缓存 token 堆叠柱图,蓝/橙/青图例
|
|
40
40
|
- 按项目筛选,鼠标悬停显示精确数值
|
|
41
|
-
-
|
|
41
|
+
- 模型明细为横向堆叠柱形图(沿用主图图例配色),列表头部右侧提供「今日 / 近 7 天 / 累计」切换标签(默认近 7 天):今日只聚合当天,近 7 天按主图同窗口排序,累计覆盖索引内全部日期(受会话持久化留存范围限制);每行附「x次 · 缓存命中 x% · 输入 xM token · 输出 xM token」明细
|
|
42
42
|
- 提供方未上报 token 用量的模型步骤不纳入统计
|
|
43
43
|
- 最近 24 小时模型/工具报错统计,默认折叠
|
|
44
44
|
|
package/client.js
CHANGED
|
@@ -313,8 +313,15 @@ window.__ModuleLoader__.load({
|
|
|
313
313
|
'usage.axis': 'token 纵轴',
|
|
314
314
|
'usage.models.more': '展开其余 {count} 个模型',
|
|
315
315
|
'usage.models.less': '收起模型列表',
|
|
316
|
-
'usage.
|
|
317
|
-
'usage.
|
|
316
|
+
'usage.modelScope.today': '今日',
|
|
317
|
+
'usage.modelScope.week': '近 7 天',
|
|
318
|
+
'usage.modelScope.all': '累计',
|
|
319
|
+
'usage.modelSortHint.today': '按今日 token 从多到少排列',
|
|
320
|
+
'usage.modelSortHint.week': '按近 7 天 token 从多到少排列',
|
|
321
|
+
'usage.modelSortHint.all': '按累计 token 从多到少排列',
|
|
322
|
+
'usage.modelBar.today': '{model}:今日 {total} token',
|
|
323
|
+
'usage.modelBar.week': '{model}:近 7 天 {total} token',
|
|
324
|
+
'usage.modelBar.all': '{model}:累计 {total} token',
|
|
318
325
|
'usage.refresh': '刷新统计',
|
|
319
326
|
'usage.refreshing': '刷新中…',
|
|
320
327
|
'usage.empty': '尚未建立使用统计索引。点击刷新统计开始只读建立索引。',
|
|
@@ -727,8 +734,15 @@ window.__ModuleLoader__.load({
|
|
|
727
734
|
'usage.axis': 'token vertical axis',
|
|
728
735
|
'usage.models.more': 'Show {count} more models',
|
|
729
736
|
'usage.models.less': 'Collapse model list',
|
|
730
|
-
'usage.
|
|
731
|
-
'usage.
|
|
737
|
+
'usage.modelScope.today': 'Today',
|
|
738
|
+
'usage.modelScope.week': 'Last 7 days',
|
|
739
|
+
'usage.modelScope.all': 'All time',
|
|
740
|
+
'usage.modelSortHint.today': 'Sorted by tokens used today, largest first',
|
|
741
|
+
'usage.modelSortHint.week': 'Sorted by tokens in the last 7 days, largest first',
|
|
742
|
+
'usage.modelSortHint.all': 'Sorted by all-time tokens, largest first',
|
|
743
|
+
'usage.modelBar.today': '{model}: {total} tokens today',
|
|
744
|
+
'usage.modelBar.week': '{model}: {total} tokens in the last 7 days',
|
|
745
|
+
'usage.modelBar.all': '{model}: {total} tokens in total',
|
|
732
746
|
'usage.refresh': 'Refresh usage',
|
|
733
747
|
'usage.refreshing': 'Refreshing…',
|
|
734
748
|
'usage.empty': 'No usage index yet. Select Refresh usage to build the read-only index.',
|
|
@@ -2820,6 +2834,8 @@ window.__ModuleLoader__.load({
|
|
|
2820
2834
|
const [modelErrorsOpen, setModelErrorsOpen] = useState(false)
|
|
2821
2835
|
const [toolErrorsOpen, setToolErrorsOpen] = useState(false)
|
|
2822
2836
|
const [modelsOpen, setModelsOpen] = useState(false)
|
|
2837
|
+
// 模型列表口径:today=仅今日 / week=近 7 天(默认,保持既有视图)/ all=宿主索引内全部日期累计。
|
|
2838
|
+
const [modelScope, setModelScope] = useState('week')
|
|
2823
2839
|
const [activeTab, setActiveTab] = useState('overview')
|
|
2824
2840
|
// 版本详情行内展开(不用浮层:弹层会被设置模态盖住)
|
|
2825
2841
|
const [channelOpen, setChannelOpen] = useState(false)
|
|
@@ -3152,6 +3168,8 @@ window.__ModuleLoader__.load({
|
|
|
3152
3168
|
const tabPanel = { padding: '14px 2px 2px', color: 'var(--dsw-alias-label-primary)' }
|
|
3153
3169
|
const inlineTab = { background: 'transparent', color: 'var(--dsw-alias-label-secondary)', border: 0, borderBottom: '2px solid transparent', padding: '8px 10px', cursor: 'pointer', fontSize: '13px', fontWeight: 550, transition: 'color 120ms, border-color 120ms' }
|
|
3154
3170
|
const inlineTabActive = { color: 'var(--dsw-alias-brand-primary)', borderBottom: '2px solid var(--dsw-alias-brand-primary)', fontWeight: 700 }
|
|
3171
|
+
// 模型列表头部的紧凑口径切换:沿用下划线标签语言,但按 11px 行高缩比。
|
|
3172
|
+
const compactTab = Object.assign({}, inlineTab, { padding: '3px 6px', fontSize: '11px' })
|
|
3155
3173
|
const sectionTitle = { fontSize: '14px', fontWeight: 700, margin: '0 0 8px', color: 'var(--dsw-alias-label-primary)' }
|
|
3156
3174
|
|
|
3157
3175
|
const formatSize = (bytes) => {
|
|
@@ -3242,23 +3260,34 @@ window.__ModuleLoader__.load({
|
|
|
3242
3260
|
const selectedProjects = usageProject === 'all'
|
|
3243
3261
|
? (usage?.projects || []).map((project) => project.id)
|
|
3244
3262
|
: [usageProject]
|
|
3245
|
-
const
|
|
3246
|
-
|
|
3247
|
-
const
|
|
3248
|
-
|
|
3263
|
+
const emptyModelTotals = (id) => ({ id, steps: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })
|
|
3264
|
+
const accumulateModelTotals = (buckets, model) => {
|
|
3265
|
+
const existing = buckets.get(model.id) || emptyModelTotals(model.id)
|
|
3266
|
+
existing.steps += model.totals.steps || 0
|
|
3267
|
+
existing.inputTokens += model.totals.inputTokens || 0
|
|
3268
|
+
existing.outputTokens += model.totals.outputTokens || 0
|
|
3269
|
+
existing.cacheReadTokens += model.totals.cacheReadTokens || 0
|
|
3270
|
+
existing.cacheWriteTokens += model.totals.cacheWriteTokens || 0
|
|
3271
|
+
buckets.set(model.id, existing)
|
|
3272
|
+
}
|
|
3273
|
+
const modelTodayTotals = new Map()
|
|
3274
|
+
const modelWeekTotals = new Map()
|
|
3275
|
+
const modelAllTotals = new Map()
|
|
3276
|
+
const weekDayKeys = new Set(usageDays.map((day) => day.key))
|
|
3277
|
+
const todayDayKey = usageDays[usageDays.length - 1].key
|
|
3278
|
+
// 累计口径遍历宿主下发的全部日期键(可早于 7 天窗口);周/今日按窗口命中累积。
|
|
3279
|
+
for (const [dayKey, source] of Object.entries(usage?.days || {})) {
|
|
3280
|
+
const targets = [modelAllTotals]
|
|
3281
|
+
if (weekDayKeys.has(dayKey)) targets.push(modelWeekTotals)
|
|
3282
|
+
if (dayKey === todayDayKey) targets.push(modelTodayTotals)
|
|
3249
3283
|
for (const project of source.projects) {
|
|
3250
3284
|
if (!selectedProjects.includes(project.id)) continue
|
|
3251
3285
|
for (const model of project.models) {
|
|
3252
|
-
const
|
|
3253
|
-
existing.steps += model.totals.steps || 0
|
|
3254
|
-
existing.inputTokens += model.totals.inputTokens || 0
|
|
3255
|
-
existing.outputTokens += model.totals.outputTokens || 0
|
|
3256
|
-
existing.cacheReadTokens += model.totals.cacheReadTokens || 0
|
|
3257
|
-
existing.cacheWriteTokens += model.totals.cacheWriteTokens || 0
|
|
3258
|
-
modelTotals.set(model.id, existing)
|
|
3286
|
+
for (const buckets of targets) accumulateModelTotals(buckets, model)
|
|
3259
3287
|
}
|
|
3260
3288
|
}
|
|
3261
3289
|
}
|
|
3290
|
+
const scopedModelTotals = modelScope === 'today' ? modelTodayTotals : modelScope === 'all' ? modelAllTotals : modelWeekTotals
|
|
3262
3291
|
const diagnosticDetail = (check) => {
|
|
3263
3292
|
const detail = String(check.detail ?? '')
|
|
3264
3293
|
if (check.id === 'session-storage' && check.status === 'ok') return translate('health.detail.session-storage.ok', { count: detail })
|
|
@@ -3297,7 +3326,7 @@ window.__ModuleLoader__.load({
|
|
|
3297
3326
|
React.createElement('span', { style: { color: 'var(--dsw-alias-label-secondary)' } }, translate(label)),
|
|
3298
3327
|
React.createElement('span', { style: { fontWeight: 650 } }, value)))
|
|
3299
3328
|
)
|
|
3300
|
-
const sortedModels = [...
|
|
3329
|
+
const sortedModels = [...scopedModelTotals.values()].sort((a, b) => modelTotalTokens(b) - modelTotalTokens(a) || b.steps - a.steps || a.id.localeCompare(b.id))
|
|
3301
3330
|
const visibleModels = modelsOpen ? sortedModels : sortedModels.slice(0, 3)
|
|
3302
3331
|
const hiddenModelCount = Math.max(0, sortedModels.length - 3)
|
|
3303
3332
|
const maxModelTokens = Math.max(1, ...visibleModels.map((model) => modelTotalTokens(model)))
|
|
@@ -3360,7 +3389,15 @@ window.__ModuleLoader__.load({
|
|
|
3360
3389
|
summaryBlock('today', 'usage.today', todayTotals),
|
|
3361
3390
|
summaryBlock('seven', 'usage.sevenDays', sevenTotals)),
|
|
3362
3391
|
React.createElement('div', { 'data-testid': 'usage-model-list', style: { marginTop: '10px', padding: '8px 10px', borderRadius: '8px', background: 'var(--dsw-alias-bg-layer-2)', border: '1px solid var(--dsw-alias-border-l1)' } },
|
|
3363
|
-
React.createElement('div', { style: {
|
|
3392
|
+
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '8px', flexWrap: 'wrap', marginBottom: '4px' } },
|
|
3393
|
+
React.createElement('div', { 'data-testid': 'usage-model-sort-hint', style: { fontSize: '11px', color: 'var(--dsw-alias-label-secondary)' } }, translate(`usage.modelSortHint.${modelScope}`)),
|
|
3394
|
+
React.createElement('div', { 'data-testid': 'usage-model-scope-tabs', style: { display: 'flex', gap: '2px' } },
|
|
3395
|
+
['today', 'week', 'all'].map((scopeId) => React.createElement('button', {
|
|
3396
|
+
key: scopeId,
|
|
3397
|
+
'data-testid': `usage-model-scope-${scopeId}`,
|
|
3398
|
+
style: Object.assign({}, compactTab, modelScope === scopeId ? inlineTabActive : { color: 'var(--dsw-alias-label-secondary)', borderBottom: '2px solid transparent' }),
|
|
3399
|
+
onClick: () => setModelScope(scopeId),
|
|
3400
|
+
}, translate(`usage.modelScope.${scopeId}`))))),
|
|
3364
3401
|
visibleModels.map((model, index) => {
|
|
3365
3402
|
const total = modelTotalTokens(model)
|
|
3366
3403
|
const fillWidth = `${Math.round(total / maxModelTokens * 10000) / 100}%`
|
|
@@ -3368,7 +3405,7 @@ window.__ModuleLoader__.load({
|
|
|
3368
3405
|
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', gap: '12px', alignItems: 'baseline', fontSize: '12px' } },
|
|
3369
3406
|
React.createElement('span', { style: { overflowWrap: 'anywhere' } }, model.id),
|
|
3370
3407
|
React.createElement('span', { style: { fontWeight: 650, whiteSpace: 'nowrap' } }, formatTokenValue(total))),
|
|
3371
|
-
React.createElement('div', { 'data-testid': `usage-model-bar-${model.id}`, 'data-value': total, 'aria-label': translate(
|
|
3408
|
+
React.createElement('div', { 'data-testid': `usage-model-bar-${model.id}`, 'data-value': total, 'aria-label': translate(`usage.modelBar.${modelScope}`, { model: model.id, total: formatTokenValue(total) }), style: { height: '8px', borderRadius: '4px', marginTop: '6px', overflow: 'hidden', background: 'var(--dsw-alias-border-l1)' } },
|
|
3372
3409
|
React.createElement('div', { style: { display: 'flex', height: '100%', width: fillWidth } },
|
|
3373
3410
|
usageSegments.map(([metricName, , color]) => {
|
|
3374
3411
|
const value = modelSegmentValue(model, metricName)
|