style(usage): refine overview card metadata

- clarify request, token, and cache summaries
- align success metrics with request outcomes
- improve performance and pricing descriptions
- move detailed breakdowns to hover tooltips
This commit is contained in:
lzt404 committed 2026-08-26 01:56:46 +08:00
1 parent 05d9ff9f0a
commit a662d35876
4 files changed
+71 -18

No files matched your search

+11 -5
View File
@@ -140,17 +140,23 @@ export const jaOverrides = {
'usage.loading': 'ローカル SQLite の使用履歴を読み込んでいます',
'usage.stat.requests': '総リクエスト数',
'usage.stat.requestMeta': '成功 {success} · 失敗 {failed} · キャンセル {canceled}',
'usage.stat.requestMetaTitle': '合計 {total} 件:成功 {success}、失敗 {failed}、キャンセル {canceled}',
'usage.stat.tokens': '合計 Token',
'usage.stat.tokenMeta': '入 {input} · 出 {output}',
'usage.stat.tokenMeta': '入力 {input} · 出力 {output}',
'usage.stat.tokenMetaTitle': '入力 {input}、出力 {output}、推論 {reasoning}、キャッシュ読取 {cache}',
'usage.stat.successRate': '成功率',
'usage.stat.reasoningMeta': '推論 {tokens}',
'usage.stat.successMeta': '成功 {success} · 失敗 {failed}',
'usage.stat.successMetaTitle': '成功 {success} 件、失敗 {failed} 件、キャンセル {canceled} 件',
'usage.stat.averageLatency': '平均レイテンシ',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · 平均レイテンシ {latency} ms',
'usage.stat.performanceMetaTitle': 'TPS {tps}、RPM {rpm}、平均レイテンシ {latency} ms',
'usage.stat.cacheHitRate': 'キャッシュヒット率',
'usage.stat.cacheHitMeta': 'キャッシュ {hit}/{input}',
'usage.stat.cacheHitMeta': 'キャッシュ読取 {hit} · 入力 {input}',
'usage.stat.cacheHitMetaTitle': 'キャッシュヒット率 {rate}%、読取 {hit} Token、入力 {input} Token',
'usage.stat.estimatedCost': '推定コスト',
'usage.stat.costMeta': '計算 {priced}/{total} · 推定',
'usage.stat.costMeta': '料金カバー率 {priced} / {total} 件',
'usage.stat.costMetaTitle': 'モデル料金で {priced} / {total} 件を推定、未計算 {unpriced} 件',
'usage.pricing.coverage': '{priced} / {total} 件を計算済み · 利用可能なモデル料金 {saved} 件',
'usage.pricing.search': 'モデルを検索',
'usage.pricing.add': '手動で追加',
+11 -5
View File
@@ -140,17 +140,23 @@ export const en: Record<MessageKey, string> = {
'usage.loading': 'Loading local SQLite usage history',
'usage.stat.requests': 'Total Requests',
'usage.stat.requestMeta': 'OK {success} · Fail {failed} · Canceled {canceled}',
'usage.stat.requestMetaTitle': '{total} requests: {success} succeeded, {failed} failed, {canceled} canceled',
'usage.stat.tokens': 'Total Tokens',
'usage.stat.tokenMeta': 'In {input} · Out {output}',
'usage.stat.tokenMeta': 'Input {input} · Output {output}',
'usage.stat.tokenMetaTitle': 'Input {input}, output {output}, reasoning {reasoning}, cache read {cache}',
'usage.stat.successRate': 'Success Rate',
'usage.stat.reasoningMeta': 'Reasoning {tokens}',
'usage.stat.successMeta': 'Success {success} · Failed {failed}',
'usage.stat.successMetaTitle': '{success} succeeded, {failed} failed, {canceled} canceled',
'usage.stat.averageLatency': 'Average Latency',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · Avg. latency {latency} ms',
'usage.stat.performanceMetaTitle': 'TPS {tps}, RPM {rpm}, average latency {latency} ms',
'usage.stat.cacheHitRate': 'Cache Hit Rate',
'usage.stat.cacheHitMeta': 'Cache {hit}/{input}',
'usage.stat.cacheHitMeta': 'Cache read {hit} · Input {input}',
'usage.stat.cacheHitMetaTitle': 'Cache hit rate {rate}%, cache read {hit} tokens, input {input} tokens',
'usage.stat.estimatedCost': 'Estimated Cost',
'usage.stat.costMeta': 'Priced {priced}/{total} · Est.',
'usage.stat.costMeta': 'Price coverage: {priced} / {total} requests',
'usage.stat.costMetaTitle': '{priced} of {total} requests estimated from model prices; {unpriced} unpriced',
'usage.pricing.coverage': '{priced} / {total} requests priced · {saved} model prices available',
'usage.pricing.search': 'Search model',
'usage.pricing.add': 'Add Manually',
+11 -5
View File
@@ -138,17 +138,23 @@ export const zhCN = {
'usage.loading': '正在读取本地 SQLite 使用记录',
'usage.stat.requests': '请求总数',
'usage.stat.requestMeta': '成功 {success} · 失败 {failed} · 取消 {canceled}',
'usage.stat.requestMetaTitle': '共 {total} 次请求:成功 {success},失败 {failed},取消 {canceled}',
'usage.stat.tokens': 'Token 总量',
'usage.stat.tokenMeta': '入 {input} · 出 {output}',
'usage.stat.tokenMeta': '输入 {input} · 输出 {output}',
'usage.stat.tokenMetaTitle': '输入 {input},输出 {output},思考 {reasoning},缓存读取 {cache}',
'usage.stat.successRate': '成功率',
'usage.stat.reasoningMeta': '思考 {tokens}',
'usage.stat.successMeta': '成功 {success} · 失败 {failed}',
'usage.stat.successMetaTitle': '成功 {success} 次,失败 {failed} 次,取消 {canceled} 次',
'usage.stat.averageLatency': '平均延迟',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · 平均延迟 {latency} ms',
'usage.stat.performanceMetaTitle': 'TPS {tps},RPM {rpm},平均延迟 {latency} ms',
'usage.stat.cacheHitRate': '缓存命中率',
'usage.stat.cacheHitMeta': '缓存 {hit}/{input}',
'usage.stat.cacheHitMeta': '缓存读取 {hit} · 输入 {input}',
'usage.stat.cacheHitMetaTitle': '缓存命中率 {rate}%,缓存读取 {hit} Token,输入 {input} Token',
'usage.stat.estimatedCost': '预估成本',
'usage.stat.costMeta': '计价 {priced}/{total} · 估算',
'usage.stat.costMeta': '价格覆盖 {priced} / {total} 次请求',
'usage.stat.costMetaTitle': '已按模型价格估算 {priced} / {total} 次请求,未计价 {unpriced} 次',
'usage.pricing.coverage': '已计价 {priced} / {total} 次请求 · 可用 {saved} 个模型价格',
'usage.pricing.search': '搜索模型',
'usage.pricing.add': '手动添加',
+38 -3
View File
@@ -692,6 +692,12 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
failed: compactNumber(overview.failureCount),
canceled: compactNumber(overview.canceledCount),
}),
metaTitle: t('usage.stat.requestMetaTitle', {
total: compactNumber(overview.totalRequests),
success: compactNumber(overview.successCount),
failed: compactNumber(overview.failureCount),
canceled: compactNumber(overview.canceledCount),
}),
},
{
label: t('usage.stat.tokens'),
@@ -700,11 +706,25 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
input: compactNumber(overview.inputTokens),
output: compactNumber(overview.outputTokens),
}),
metaTitle: t('usage.stat.tokenMetaTitle', {
input: compactNumber(overview.inputTokens),
output: compactNumber(overview.outputTokens),
reasoning: compactNumber(overview.reasoningTokens),
cache: compactNumber(overview.cacheReadTokens),
}),
},
{
label: t('usage.stat.successRate'),
value: `${overview.successRate.toFixed(1)}%`,
meta: t('usage.stat.reasoningMeta', { tokens: compactNumber(overview.reasoningTokens) }),
meta: t('usage.stat.successMeta', {
success: compactNumber(overview.successCount),
failed: compactNumber(overview.failureCount),
}),
metaTitle: t('usage.stat.successMetaTitle', {
success: compactNumber(overview.successCount),
failed: compactNumber(overview.failureCount),
canceled: compactNumber(overview.canceledCount),
}),
},
{
label: t('usage.stat.tps'),
@@ -713,6 +733,11 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
rpm: overview.rpm.toFixed(2),
latency: Math.round(overview.averageLatencyMs),
}),
metaTitle: t('usage.stat.performanceMetaTitle', {
tps: overview.tps.toFixed(1),
rpm: overview.rpm.toFixed(2),
latency: Math.round(overview.averageLatencyMs),
}),
},
{
label: t('usage.stat.cacheHitRate'),
@@ -721,6 +746,11 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
hit: compactNumber(overview.cacheReadTokens),
input: compactNumber(overview.inputTokens),
}),
metaTitle: t('usage.stat.cacheHitMetaTitle', {
rate: (overview.cacheHitRate * 100).toFixed(1),
hit: compactNumber(overview.cacheReadTokens),
input: compactNumber(overview.inputTokens),
}),
},
{
label: t('usage.stat.estimatedCost'),
@@ -729,17 +759,22 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
priced: compactNumber(overview.pricedRequests),
total: compactNumber(overview.totalRequests),
}),
metaTitle: t('usage.stat.costMetaTitle', {
priced: compactNumber(overview.pricedRequests),
total: compactNumber(overview.totalRequests),
unpriced: compactNumber(Math.max(overview.totalRequests - overview.pricedRequests, 0)),
}),
},
];
return (
<div className="usage-overview-layout">
<div className="usage-stat-grid">
{cards.map(({ label, value, meta }) => (
{cards.map(({ label, value, meta, metaTitle }) => (
<article className="panel usage-stat-card" key={label}>
<span className="usage-stat-card-label">{label}</span>
<strong className="usage-stat-card-value">{value}</strong>
<small className="usage-stat-card-meta" title={meta}>
<small className="usage-stat-card-meta" title={metaTitle ?? meta}>
{meta}
</small>
</article>