fakeNihilist/dsh-plugin-usage-stats ↗★ 0

dsh-plugin-usage-stats

Whole-corpus token usage statistics: daily and cumulative tokens, cache hit rate, per-model breakdown, and a year-long activity heatmap. 适合需要监控、分析和统计历史对话Token消耗情况的用户。

패키지
dsh-plugin-usage-stats
호환성
미검증
버전
1.0.0
라이선스
MIT
최근 업데이트
2026. 9. 24.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:fakeNihilist/dsh-plugin-usage-stats

dsh-plugin-usage-stats

跨全部会话的 token 用量统计插件(DSH)。在 Web GUI 左侧栏新增「用量统计」入口,主区域打开整页仪表盘。

用量统计仪表盘

Whole-corpus token usage statistics for DSH: a sidebar entry plus the dashboard it opens.

只做一件事

插件只回答一个问题:这些会话一共用了多少 token。除此之外它什么都不做。

  • 没有设置项。 安装即用,没有配置文件、没有需要调的参数。唯一的交互是一个「刷新」和一组 7 天 / 30 天 / 全部的时间范围切换。
  • 没有估算。 所有数字直接取自 adapter 上报的 usage,不推断、不按字数折算、不补零。
  • 不碰模型。 不注册工具、不注入提示词、不修改请求,对模型完全不可见,不影响 prompt 与 KV 缓存。
  • 单一职责。 一个入口、一个整页、一条只读路由(GET /api/usage-statistics.data)。所有区块共用同一份载荷与同一个时间窗口,不存在「图看的是 7 天、表算的是 30 天」这种漂移。
  • 无额外依赖。 宿主半是纯 Node 模块,客户端半是浏览器可直接加载的 bundle,没有构建步骤,也没有第三方运行时依赖。

功能

页面是一份整页报告,控件只有两个:整页的「刷新」,以及一组 7 天 / 30 天 / 全部的时间范围切换。后者只改视图窗口,载荷与统计口径不变,因此不存在「被悄悄过滤掉」的数据。时间范围控件独立成一行,同时驱动下面三块视图,三块共用一个窗口。

  • 概览卡片:当日 Token / 累计 Token(各带输入、输出、缓存读拆分);缓存命中率(附当日缓存率、当日与累计请求数)
  • Token 活动:一年期日热力图,GitHub 风格蓝色四级色阶;月份标签按实际渲染宽度排布、碰撞时自动丢弃,悬停任意格子显示该日全部指标
  • 每日 Token 趋势图:堆叠柱状图(输入 + 输出),外加一条更宽的浅黄色命中率柱取右轴 0–100%,作为当天堆叠的背景板
  • 模型用量环图:左侧环图 + 右侧图例(模型名 + 占比 + token 数),悬停扇区或图例显示占比、调用数、缓存率;窄卡片自动回落成上下单列
  • 按模型明细表:按供应商分组,列有模型、调用数、未缓存输入、输出、缓存读、缓存率、合计;表内滚动、表头吸顶
  • 悬停读数统一用 K/M/B 单位:热力图格子与趋势柱的读数里,token 值一律缩写成 698.9M 这样的量级,不打印完整数字——一天的用量动辄上亿位,完整数字在浮层里根本读不出来。调用数是计数而非量级,仍是整数;缓存率仍是百分比。需要精确数字时看概览卡片的附注与明细表,它们始终是完整值。

「全部」一档等于语料自身的跨度:如果只有 7 天 / 30 天两档,任何在更早时间用过的模型都会从环图与明细表中消失,加上「全部」后所有模型都可见。

整页与「插件」页同宽(960px 居中列)。

数据来源

会话事件 assistant/message 自带 usage:

{ inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, totalTokens }

计数互不重叠 —— inputTokens 仅为未缓存输入,计费输入 = 三者之和。模型归属取自该事件之前最近一次 request/header 的 config.provider / config.model。

路由:GET /api/usage-statistics.data?days=,默认 371 天(一年热力图)。days 是下限而非上限:语料比它更老时,窗口会回退到语料起点,否则早期模型会从环图与明细表里永久消失。走共享 /api 通道鉴权,因此只能在浏览器内(已登录)访问。

热力图与趋势图使用两个独立的窗口:payload.days(热力图)始终是整段请求窗口,payload.trend.days(趋势 / 环图 / 明细表)则从语料第一天起。这样热力图保留一年上下文,而「全部」不会用几个月的空列把新语料垫满。

其他实现要点:

  • 持久化日志的时间戳字段是 time;时区偏移的符号约定为东为正,日界据此划分本地日期。
  • fork 子会话的日志开头是父会话前缀的副本,插件按 inherited: true 标签的 session/end-seed 标记位置去重,避免把父会话的 token 重复计入;不带该标签的 session/end-seed 是普通生命周期边界,不作为切点。
  • 旧格式(v0)归档中迁移层拒绝读取的部分,插件会直接读取其中的结算事件并计入(上报为 recoveredSessions);语料扫描每个进程只跑一次,不可读会话计入永久集合,计数器不会随轮询增长。
  • 冷启动扫描与实时折叠按「归属」切分会话,同一笔结算只会被计入一次:扫描列出的会话归扫描(它读整份日志,实时事件要等扫描留下的游标接手,否则同一笔会被计两遍);扫描没列出的会话没有任何别的来源,由实时折叠从它的第一个事件起接管 —— 服务运行期间新建的每个会话都属于后者,漏掉它们会让「当日 Token」只剩上次重启时盘上已有的那点数据。扫描还没跑过时两者无法区分(既可能是刚新建的会话,也可能是用户抢在扫描前恢复的旧会话,而扫描会把旧会话整份折叠),因此此时不认领任何会话;扫描彻底读不了的会话则从「扫描归属」里释放,交给实时折叠。

安装