Bundle
dsh-token-usage-cost
会话 token 用量与费用速览:每轮结束显示本轮 token/费用 chip,输入条上方显示会话累计费用。价格自动拉取(LiteLLM 价格表,host 侧缓存)+ 按模型手动覆盖 + 汇率换算。纯 UI 展示,不进入模型上下文。
- Source
- arthur20150522
- stars
- 2 stars
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-token-usage-cost
DSH(DeepSeek Harness)Web 界面的 **token 用量与费用速览**插件。纯 UI 展示,**绝不进入模型上下文**、不影响会话与 token 统计。
```
… assistant 回答 …
本轮 · ¥0.0123 · ↑2.9K ↓328 · GLM5.3F ← 每轮 chip(模型色 + 悬浮明细)
─────────────────────────────────────────────
1 轮 · 2 步 | LLM 14.6s · … | 缓存命中 33% | 输入 2.9K tok · 输出 328 tok
本会话 ¥0.157 · ↑12.4K ↓2.1K · glm-5.3 ⚙ ← 会话累计行(⚙ 编辑价格配置)
```
## 功能
- **每轮费用 chip**:每轮(一次提问 → 回答 + 工具调用)结束后,在该轮的复制/反馈操作栏中常驻显示
`本轮 · 费用 · ↑输入 ↓输出 · 模型短名`;单模型的费用与短名使用同一稳定颜色,多模型则分别着色,悬浮可见实际模型、时段、四计费桶与单价来源。
- **会话累计行**:输入条上方状态行下方,显示整场会话累计费用、token;同会话切过模型时显示“多模型”。
- **自动拉取价格表**:四个内置权威源并发拉取、自动识别格式后合并成一张大表(实测 9600+ 条目),host 侧磁盘缓存(默认 7 天 TTL):
| 源 | 格式 | 覆盖 |
|---|---|---|
| LiteLLM 社区表(gh-proxy 镜像 / 直连) | `input_cost_per_token` 等,USD/token | 2600+ 通用模型 |
| [OpenRouter](https://openrouter.ai/api/v1/models) `/api/v1/models` | `pricing.prompt` 等,USD/token(字符串) | 最新 GLM/DeepSeek 全系(含 glm-5.3-flash) |
| [models.dev](https://models.dev/api.json) `/api.json` | `cost.input` 等,原生 USD/1M | zhipuai/deepseek/openai 等官方档 |
- **⟳ 一键对账同步**:⚙ 编辑器里的同步按钮 = 拉全部价格源 **× 枚举你 DSH 已配置的模型**(llm 适配器目录)→ 逐个自动匹配 → 后缀命中的映射**自动写回 `modelMap` 配置**(不覆盖你手动写的);未匹配的列出清单,提示去 overrides 补。
- **按模型配置费用**:三层解析,优先级从高到低
1. `overrides` 手动覆盖(价格表没有的私有/新模型)
2. `modelMap` 模型映射(同步按钮自动补全;你也可以手写)
3. 价格表精确 key → 后缀匹配(段数少者优先官方直供档,自动剔除"套餐免费全 0"假价格)
- **峰谷 / 时段价**:可配置 IANA 时区和任意多个 `timeBands`。每条模型调用按其历史发生时间匹配时段;
时段可设置基础价倍率 `multiplier`、模型专属倍率 `modelMultipliers`,或针对模型设置最终单价 `overrides`,支持跨午夜(如 `22:00` → `06:00`)。
- **历史模型归因**:从 DSH 全量 `session.history` 中读取每条 `assistant/message` 自带的 `provider/model` 和事件时间。
因此同一轮中的模型切换、工具调用后的再次模型调用都会分别计价,不会用当前模型重算旧步骤。
- **币种与汇率**:默认 ¥ 人民币(可配汇率),也可切 $ 美元原价显示。
- **⚙ 迷你编辑器**:点会话累计行末尾的 ⚙,直接在页面里改币种/汇率/峰谷时段/映射/覆盖、一键对账同步。
数据来源:费用优先读取 DSH 全量 `session.history` 中每条 `assistant/message` 的 `usage`、`message.source` 与事件时间;初次加载期间才回退到当前窗口节点 / `tokenUsage` 投影。企业计费口径下 `reasoningTokens` 单独保留、不并入输出桶。费用 = Σ(每条调用的四计费桶 × 该条模型在该时段的单价)。
## 安装
### 从 GitHub 安装
```powershell
dsh plugin --profile web add github:arthur20150522/dsh-token-usage-cost
# 然后重启 dsh web
```
安装包自带 `dsh.bundle` 和 `cordis.patch.yml`,会自动挂载,无需手改 profile 的 patch 文件。
### 本机开发目录 → link 进 profile
前提:本机有 Node ≥ 18 与 pnpm;插件目录无需构建(零依赖纯 JS)。
```powershell
# 在插件目录里执行(脚本会把插件以 link: 依赖装进 web profile 并挂载)
cd F:\LowUseCodeHome\随手记录\dsh-token-usage-cost
.\install.ps1 # 默认 profile=web;-Profile 可指定其他 profile
# 然后重启 dsh web(关掉 launcher 再启动)
```
`install.ps1` 做三件事(均有时间戳备份,可回滚):
1. `<profile>\package.json` 增加依赖 `"dsh-token-usage-cost": "link:<本目录>"`(符号链接,改本目录代码重启即生效);
2. 在 profile 目录跑 `pnpm install`;
3. `<profile>\cordis.patch.yml` 追加挂载项:
```yaml
- insert:
- id: ui-token-usage-cost
name: 'dsh-token-usage-cost'
```
卸载:`.\uninstall.ps1`(反向移除三项)。
## 配置
配置文件:`~/.dsh/dsh-token-usage-cost.json`(也可用 ⚙ 编辑器改)。
```jsonc
{
"currency": "CNY", // 'CNY' | 'USD'
"usdRate": 7.2, // 1 USD 兑换(currency=USD 时忽略)
"timeZone": "Asia/Shanghai", // 峰谷规则使用的 IANA 时区
"fetchEnabled": true,
"ttlHours": 168, // 价格缓存有效期
// 价格源列表:全部并发拉取后按顺序合并,越靠前越优先。
// 支持三种格式,自动识别;可以加任意镜像前缀(如 gh-proxy.com/https://...)。
"sourceUrls": [
"https://gh-proxy.com/https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
"https://openrouter.ai/api/v1/models",
"https://models.dev/api.json"
],
// 模型映射:DSH 里显示的"provider/模型名" → 价格表 key。
// 「⟳ 同步」按钮会自动补全这里的映射;你手写的键同步时永远不会被覆盖。
"modelMap": {
"zhipuai/glm-5.3-flash": "z-ai/glm-5.3-flash"
},
// 手动价格覆盖:单位 USD / 1M token,优先级最高(四种字段都可选,
// 但 input/output 必填)。适合价格表没有的私有模型,或想对齐平台实际计费时使用。
"overrides": {
"glm-5.3-flash": { "input": 0.075, "output": 0.25, "cacheRead": 0.015, "cacheWrite": 0.075 }
},
// 数组顺序即优先级;不需要峰谷价时写 []。
"timeBands": [
{ "name": "谷", "start": "00:00", "end": "08:00", "multiplier": 0.5 },
{
"name": "峰",
"start": "08:00",
"end": "24:00",
// overrides 是这个时段的最终 USD / 1M 单价,不再套 multiplier。
"overrides": {
"glm-5.3-flash": { "input": 0.111111, "output": 0.388889, "cacheRead": 0.031944 }
}
},
// 仅工作日、仅指定模型的高峰倍率;key 使用 DSH 实际 provider/model。
{
"name": "DeepSeek V4 Flash 高峰",
"weekdays": [1, 2, 3, 4, 5],
"start": "09:00",
"end": "12:00",
"modelMultipliers": {
"deepseek4399/deepseek-v4-flash-vision-exp": 2,
"deepseek4399new/deepseek-v4-flash-vision-exp": 2
}
},
{
"name": "DeepSeek V4 Flash 高峰",
"weekdays": [1, 2, 3, 4, 5],
"start": "14:00",
"end": "18:00",
"modelMultipliers": {
"deepseek4399/deepseek-v4-flash-vision-exp": 2,
"deepseek4399new/deepseek-v4-flash-vision-exp": 2
}
}
]
}
```
**overrides / modelMap 填写速查**:
- key 写 DSH 里的模型标识:完整 `provider/model` 或裸 `model` 都能命中;
- overrides 的 value 只要求 `input`、`output` 两个数字(USD/1M),`cacheRead`/`cacheWrite` 缺省时按输入价估算;
- modelMap 的 value 必须是价格表里**存在的 key**(同步按钮自动写的都是校验过的);不确定 key 名,先点一次 ⟳ 同步看报告里命中了哪条;
- `timeBands` 的 `start` / `end` 是 `HH:mm`,`end` 允许写 `24:00`;跨午夜写法如 `22:00` → `06:00`;重叠时数组中靠前的规则优先;
- `weekdays` 可选,按本地时区的星期匹配:`0` 是周日、`1` 是周一、…、`6` 是周六;省略则每天生效;
- 时段 `overrides` 会优先于全局 `overrides`;未配置时段 `overrides` 时,先匹配 `modelMultipliers`(模型专属倍率),未命中才用该时段全局 `multiplier`;两者都会缩放基础价(包括全局 `overrides`);
- 改完保存即生效(client 实时重读配置),无需重启。
REST(仅 loopback):
| 路由 | 方法 | 说明 |
|---|---|---|
| `/api/dsh-token-usage-cost/config` | GET / POST | 读 / 浅合并写配置 |
| `/api/dsh-token-usage-cost/prices` | GET | 价格表(过期自动重拉) |
| `/api/dsh-token-usage-cost/refresh` | POST | 强制重拉 |
| `/api/dsh-token-usage-cost/sync` | POST | **对账**:强拉价格源 × 枚举已配置模型 → 匹配 + 写回 modelMap + 返回未匹配清单 |
## 已知边界
- **模型中途切换**:新日志直接使用每条 `assistant/message.source` 的实际模型;旧日志缺少 `source` 时回退到前序 `request/header` / `request/context`。两者都缺失时才使用当前模型作为近似值。
- **历史价格版本**:模型与峰谷时段按历史事件精确归因,但单价来自当前插件配置 / 当前缓存的价格表;你之后修改价格规则,历史会话会按新规则重算。
- **事件时间缺失**:极旧或异常日志没有事件时间时,该条调用不匹配峰谷规则,回退基础单价。
- **匹配到非官方档**:同名模型在多个供应商下存在时,优先选段数少的官方直供档并剔除全 0 的套餐假价;仍不对就用 `overrides` 盖掉。
- **缓存单价缺失**:个别模型价格表无缓存价时按输入单价估算(tooltip 会注明)。
- **token 统计本身**以 DSH token-meter 为准;本插件只做乘法。
## 开发与发布
- 零构建链:`lib/index.js`(host,ESM)+ `lib/client.js`(client,factory CJS classic script)。改 host 需重启 dsh web;改 client.js 刷新页面即可生效(bundle 按请求实时读盘)。
- 本地单测:`node test\run-tests.mjs`(114 个断言:多源格式识别/合并/对账引擎/模型短名与颜色/峰谷时段/历史模型归因/币种换算/slot 注册契约)。
- 发布给同事:
- 推荐 GitHub 安装:`dsh plugin --profile web add github:arthur20150522/dsh-token-usage-cost`;
- 或直接把整个目录打成 ZIP 发给同事,解压后运行 `install.ps1`;
- 发布 npm 包后,可改用:`dsh plugin --profile web add dsh-token-usage-cost`。
## 文件结构
```
dsh-token-usage-cost/
├── package.json # exports["./client"] + dsh.client 声明(client 插件识别点)
├── lib/index.js # host:配置持久化 + 价格拉取/归一化/缓存 + REST(loopback)
├── lib/client.js # client:价格引擎 + assistant-actions chip + dock 累计行 + ⚙ 编辑器
├── test/run-tests.mjs # 离线单测(node 直接跑)
├── install.ps1 # link 安装 + patch 挂载
├── uninstall.ps1
└── README.md
```
MIT License.
Install
dsh plugin --profile web add github:arthur20150522/dsh-token-usage-cost
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-token-usage-cost from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.