- Início
- Plugins
- Uso e cobrança
- dsh-usage-display
dsh-usage-display
deluo/dsh-usage-display
多厂商余额/用量徽标(内置 DeepSeek 余额与智谱 GLM Coding Plan 配额):host 侧按轮次事件取数,经 SSE 同步到浏览器展示。
Instalar
dsh plugin --profile web add github:deluo/dsh-usage-displayREADME
dsh-usage-display
在 dsh Web 界面显示模型厂商余额 / 套餐用量的会话头部徽标插件。host 进程从各家 厂商官方接口取数并缓存,浏览器侧只读本地路由渲染;API key 始终留在 host, 不会下发到浏览器。
内置三家厂商,按多厂商适配器架构组织,新增厂商只需实现一个 adapter:
| 厂商 | providerId | 展示内容 |
|---|---|---|
| DeepSeek | deepseek | 多币种账户余额(granted / topped-up 拆分) |
| MiniMax | minimax | Token Plan 配额(5 小时窗口与周窗口) |
| 智谱 GLM | zhipu | Coding Plan 配额(5h、周限额、工具用量三个百分比) |
效果预览
设置页(Settings → Plugins → “用量与余额”)可按通用显示 / DeepSeek / MiniMax / 智谱 GLM 分区调整展示偏好与告警阈值,保存后立即生效:

特性
- 会话头部用量徽标:展示当前模型对应厂商的主指标,点击展开明细面板并支持手动刷新。
- 可配置告警阈值:余额低于阈值、配额用量超过阈值时,徽标状态点与进度条按 warn(黄)/ critical(红)两级染色。
- 可配置进度可视化:percent 类指标在徽标与面板中支持文本、环形图、条形图三种
形态(
display.panelStyle),徽标可用auto按指标类型自动选择。 - 设置页热更新:Settings → Plugins → “用量与余额”页可即时调整展示偏好与告警 阈值,保存后 host 重建运行时并重新取数,无需重启;接入类字段仍走 cordis 配置。
- 真正产生模型调用后自动取数:
turn/start与turn/end各全量刷新一次,切换模型时 只定向刷新新选中的厂商。 - host 刷新落定后通过 SSE 通知浏览器重读本地缓存;浏览器绝不直连厂商 API。
- 每家厂商独立缓存与故障隔离:一家失败不影响其他家,失败时保留上次成功值并标注更新时间。
- 凭证只以引用名出现在配置中,每次取数由 dsh 凭证服务实时解析,轮换后下次请求即生效。
前置要求
- Node.js(与运行中的 dsh 相同的版本即可)
- pnpm
- dsh CLI ≥ 0.1.0-rc.6
安装
从源码安装(开发)
# 1. 安装依赖并构建(产出 lib/index.js 与 lib/client.js)
pnpm install
pnpm run build
# 2. 安装进 web profile(在插件目录内执行 `add .` 等价;-w 按 workspace 链接)
dsh plugin --profile web add -w D:/Code/dsh-usage-display
# 3. 验证组合层,然后启动
dsh web --dump-config
dsh web
Windows 下路径务必用正斜杠,反斜杠会被解析成非法包名(如 Codedsh-usage-display)。
-w 需要保留:profile 自带 pnpm-workspace.yaml。
卸载:dsh plugin --profile web remove dsh-usage-display。
分发形式
- npm:
pnpm add dsh-usage-display(或npm i dsh-usage-display)后执行dsh plugin --profile web add dsh-usage-display;prepare脚本会在安装时构建。 - tarball:
pnpm pack后执行dsh plugin --profile web add ./dsh-usage-display-<version>.tgz, 分发的是预构建产物,用户侧无需构建授权。 - Git 安装:
dsh plugin --profile web add github:deluo/dsh-usage-display。源码包由prepare脚本构建;pnpm ≥ 10 默认拒绝,需按提示在该 profile 的pnpm-workspace.yaml中给allowBuilds授权后重试。
配置
默认配置见 cordis.patch.yml,用户可在 profile 或 home 级的
cordis.patch.yml 中覆盖(后应用层整行替换):
dsh-usage-display:
display:
badgeStyle: 'auto' # auto | text | ring | bar;徽标上的进度形态
panelStyle: 'ring' # text | ring | bar;面板里 percent 指标的形态
showResetCountdown: true # 徽标配额文案是否带“距重置”倒计时
providers:
deepseek:
enabled: true # 关闭后显示“已停用”,不再取数
routeIds: ['deepseek-official'] # dsh provider 路由 id → 本插件 providerId(providerId 自动补入)
apiKeyEnv: 'DEEPSEEK_API_KEY' # 凭证引用名,不是 key
baseURL: 'https://api.deepseek.com'
badgeCurrency: 'CNY' # 徽标主币种;账户无此币种时保持接口返回顺序
warnBelow: 10 # 余额低于此值 → warn;'off' 关闭
criticalBelow: 5 # 余额低于此值 → critical;'off' 关闭
minimax:
enabled: true
routeIds: ['minimax', 'minimax-cn', 'minimaxi', 'minimax-coding-plan', 'minimax-token-plan']
apiKeyEnv: 'MINIMAX_API_KEY' # 只存引用名,key 由 host 运行时解析
apiKeyAliases:
[
'MINIMAX_TOKEN_PLAN_API_KEY',
'MINIMAX_CODING_PLAN_API_KEY',
'MINIMAX_CODING_API_KEY',
'MINIMAX_CN_API_KEY',
'MINIMAX_API_KEY',
'MINIMAX_API_TOKEN',
]
baseURL: 'https://api.minimaxi.com' # 含 minimaxi.com 走国内站,否则走 api.minimax.io
badgeMetric: '5h' # 徽标主指标:5h | weekly
resetTimeStyle: 'countdown' # 重置时间:countdown 倒计时 | time 本地时间点
warnAbovePercent: 80 # 用量超过此百分比 → warn;'off' 关闭
criticalAbovePercent: 90 # 用量超过此百分比 → critical;'off' 关闭
zhipu:
enabled: true
routeIds: ['zai-coding-cn', 'zai-coding', 'zai', 'glm', 'zhipu', 'bigmodel', 'zhipuai']
apiKeyEnv: 'ZHIPU_API_KEY'
apiKeyAliases:
[
'ZAI_CODING_CN_API_KEY',
'ZAI_CODING_API_KEY',
'GLM_API_KEY',
'ZAI_API_KEY',
'BIGMODEL_API_KEY',
]
baseURL: 'https://open.bigmodel.cn'
authStyle: 'raw' # 'raw' | 'bearer'
badgeMetric: '5h' # 徽标主指标:5h | weekly | tools
resetTimeStyle: 'countdown' # 重置时间:countdown 倒计时 | time 本地时间点
warnAbovePercent: 80 # 用量超过此百分比 → warn;'off' 关闭
criticalAbovePercent: 90 # 用量超过此百分比 → critical;'off' 关闭
公共字段:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | true | 关闭后徽标显示“用量已停用”,不再取数 |
routeIds | string[] | [] | dsh provider 路由 id → 本插件 providerId,用于模型切换联动;providerId 本身总会自动加入映射 |
展示偏好(插件级 display):
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
badgeStyle | 'auto' | 'text' | 'ring' | 'bar' | 'auto' | 徽标进度形态;auto 对 percent 指标用迷你条形图、金额保持纯文本 |
panelStyle | 'text' | 'ring' | 'bar' | 'ring' | 面板中 percent 指标的形态 |
showResetCountdown | boolean | true | 徽标配额文案是否带“距重置”倒计时 |
DeepSeek 专属:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
routeIds | string[] | ['deepseek-official'] | DeepSeek 官方 harness 适配器上报的 provider 路由 id;deepseek 作为 providerId 仍会自动加入 |
apiKeyEnv | string | DEEPSEEK_API_KEY | 凭证引用名,请求 GET {baseURL}/user/balance 时使用 |
baseURL | string | https://api.deepseek.com | 余额接口前缀 |
badgeCurrency | string | CNY | 徽标主币种(按接口返回的 currency 匹配,大小写不敏感);无此币种时保持接口顺序 |
warnBelow | number | 'off' | 10 | 余额低于此值徽标变黄 |
criticalBelow | number | 'off' | 5 | 余额低于此值徽标变红 |
智谱专属:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
apiKeyEnv | string | ZHIPU_API_KEY | 首选凭证引用名 |
apiKeyAliases | string[] | 见上 | 首选未配置时按顺序回退;指向模型适配器已在用的引用名即可直接复用其 key |
baseURL | string | https://open.bigmodel.cn | 实际请求 host 按域名路由:含 bigmodel.cn → open.bigmodel.cn,否则 api.z.ai |
authStyle | 'raw' | 'bearer' | 'raw' | 首选鉴权头风格;401/403 自动换另一种重试,非法值在配置层直接报错 |
badgeMetric | '5h' | 'weekly' | 'tools' | '5h' | 徽标主指标 |
resetTimeStyle | 'countdown' | 'time' | 'countdown' | 重置时间展示:countdown 显示紧凑倒计时(如 2h13m、2d3h);time 显示本地时间点(如 15:30、明天 08:30) |
warnAbovePercent | number | 'off' | 80 | 用量超过此百分比徽标变黄 |
criticalAbovePercent | number | 'off' | 90 | 用量超过此百分比徽标变红 |
MiniMax Token Plan 专属:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
routeIds | string[] | ['minimax', 'minimax-cn', 'minimaxi', 'minimax-coding-plan', 'minimax-token-plan'] | dsh provider 路由 id → 本插件 providerId |
apiKeyEnv | string | MINIMAX_API_KEY | 首选凭证引用名 |
apiKeyAliases | string[] | 多个 Token Plan / Coding Plan / CN 别名 | 首选未配置时按顺序回退 |
baseURL | string | https://api.minimaxi.com | 区域识别基准地址;含 minimaxi.com 走国内站,否则走 api.minimax.io |
badgeMetric | '5h' | 'weekly' | '5h' | 徽标主指标 |
resetTimeStyle | 'countdown' | 'time' | 'countdown' | 重置时间展示形态 |
warnAbovePercent | number | 'off' | 80 | 用量超过此百分比徽标变黄 |
criticalAbovePercent | number | 'off' | 90 | 用量超过此百分比徽标变红 |
warn* / critical* 配反(如 warnBelow 小于 criticalBelow)时按更严格的方向归一;
全部设为 'off' 关闭该厂商的告警染色。
配置里从不出现 key 本身。apiKeyEnv / apiKeyAliases 都是凭证引用名,host 每次取数时
经 ctx.credentials.resolve() 解析:进程环境优先,其次 $DSH_HOME/.credentials.yaml
(Models 页 / dsh credentials set 写入),再以项目与用户的 .env 回退。模型侧已配置的
智谱 key 可以直接复用——把 apiKeyEnv 指向模型适配器所用的引用名(dsh web --dump-config
可查到);托管存储里的 key 变更下次取数即生效,进程 env 的快照在启动时冻结。
使用
- 打开会话后,头部操作区出现用量徽标:DeepSeek 显示余额金额,MiniMax 与智谱显示 配额窗口的已用百分比与重置时间;命中告警阈值时状态点与进度条变黄/红。
- 徽标左侧的状态点只在纯文本/金额模式与异常状态时出现;有迷你条形图或环形图时 颜色信息已由图形表达,状态点自动隐藏。
- 点击徽标展开当前模型对应厂商的明细面板,含状态、指标明细(金额行 / 配额表)、
更新时间与“刷新”按钮;配额指标按
display.panelStyle渲染为环形图、条形图或 纯数字表格。手动刷新会等待真实取数落定。 - MiniMax 与 GLM 配额重置时间都支持两种形态:
countdown显示2h13m/2d3h等 倒计时,time显示15:30、明天 08:30、周三 08:30等本地时间点。 - 在 Settings → Plugins → “用量与余额”页按“通用显示 / DeepSeek / MiniMax / 智谱 GLM”分区,
保存后立即生效。该页写入的是用户设置文档;
enabled/routeIds/apiKeyEnv/baseURL/authStyle等接入类字段不在此暴露,仍在 cordis.patch.yml 中维护。 - 切换模型时徽标高亮立即跟随(读模型选择目录 store);取数仍由轮次事件驱动, 切换后尚未发消息时展示的是缓存快照。
- 当前模型的厂商未接入(
routeIds未覆盖)时徽标进入中性态显示“其他厂商”,面板列出 全部已接入厂商。 - 每家厂商有五态:
loading/ok/unconfigured/disabled/error;失败时展示 上次成功值并标注原更新时间。
本地 HTTP 接口
调试与二次集成用:
GET /plugins/dsh-usage-display/balance[?refresh=1] # 聚合快照;refresh=1 强制真实取数
GET /plugins/dsh-usage-display/events # SSE:balance-updated 事件 + 15s 心跳
/balance 只接受 GET,其余方法返回 405。响应示例:
{
"providers": [
{
"providerId": "deepseek",
"displayName": "DeepSeek",
"kind": "balance",
"status": "ok",
"isAvailable": true,
"metrics": [
{
"key": "cny",
"label": "CNY 余额",
"kind": "amount",
"remaining": 110.0,
"unit": "CNY",
"detail": { "granted": "10.00", "toppedUp": "100.00" },
"severity": "ok"
}
],
"fetchedAt": "2026-08-18T10:00:00.000Z",
"cached": false,
"severity": "ok"
},
{
"providerId": "minimax",
"displayName": "MiniMax Token Plan",
"kind": "quota",
"status": "ok",
"isAvailable": true,
"plan": "Max",
"metrics": [
{
"key": "5h",
"label": "5h限额",
"kind": "percent",
"used": 28,
"resetsAt": "2026-08-18T13:00:00.000Z"
},
{ "key": "weekly", "label": "周限额", "kind": "percent", "used": 45 }
],
"fetchedAt": "2026-08-18T10:00:00.000Z",
"cached": false
},
{
"providerId": "zhipu",
"displayName": "智谱 GLM",
"kind": "quota",
"status": "ok",
"isAvailable": true,
"plan": "pro",
"metrics": [
{
"key": "5h",
"label": "5h限额",
"kind": "percent",
"used": 28,
"resetsAt": "2026-08-18T13:00:00.000Z"
},
{ "key": "weekly", "label": "周限额", "kind": "percent", "used": 12 },
{ "key": "tools", "label": "工具用量", "kind": "percent", "used": 8 }
],
"fetchedAt": "2026-08-18T10:00:00.000Z",
"cached": false
}
],
"activeBySession": { "<会话id>": { "providerId": "zhipu", "model": "glm-4.7" } },
"routes": {
"deepseek-official": "deepseek",
"deepseek": "deepseek",
"minimax": "minimax",
"minimax-cn": "minimax",
"zai": "zhipu",
"glm": "zhipu"
},
"display": { "badgeStyle": "auto", "panelStyle": "ring", "showResetCountdown": true },
"providerDisplay": {
"minimax": { "resetTimeStyle": "countdown" },
"zhipu": { "resetTimeStyle": "countdown" }
}
}
普通读只返回本地缓存(cached: true),不会触发厂商 API;?refresh=1 等待取数并返回
新鲜快照(cached: false)。
项目结构
dsh-usage-display/
├── package.json # 双面插件声明(dsh.bundle + dsh.client)
├── cordis.patch.yml # host loader 行与默认配置
├── tsconfig.json # 类型检查配置
├── tsdown.config.ts # host / client 双 bundle 构建
├── scripts/
│ ├── smoke-client.mjs # 客户端 bundle 冒烟测试
│ └── smoke-host.mjs # host 编排冒烟测试
└── src/
├── index.ts # host 入口:HTTP 路由 + SSE + 会话事件编排
├── types.ts # 两侧共用的快照 / 指标契约
├── settings.ts # 设置页可调子集目录(各厂商 tunable 类型聚合)
├── core/
│ ├── registry.ts # 厂商注册表:schema / tunable 抽取合并 / 展示偏好聚合
│ └── usage-service.ts # 缓存 / in-flight 去重 / 故障隔离
├── providers/
│ ├── types.ts # ProviderAdapter SPI
│ ├── deepseek.ts # DeepSeek 余额适配器
│ ├── minimax.ts # MiniMax Token Plan 配额适配器
│ └── zhipu.ts # 智谱 GLM 配额适配器
└── client/
├── index.ts # 浏览器入口:读取快照 + 注册徽标
├── routes.ts # 本地路由常量(与 host 侧对齐)
├── usage-store.ts
├── UsageBadge.tsx
└── SettingsTab.tsx # 设置页(Plugins 分区 tab)
接入新厂商
- 在
src/providers/<id>.ts实现ProviderModule,fetch()负责取数并把 wire 格式 归一化为ProviderSnapshot(异常在内部吞掉并返回error快照,正常路径不 throw); 指标kind支持amount/window/percent。如需设置页热更新,模块里声明tunable(schema + extract + merge)与可选的display偏好,字段默认值只在模块内 维护一份。 - 在
src/index.ts的createRegistry([deepseek, minimax, zhipu])中登记模块,并在SETTINGS_SCHEMA里补一行该厂商的tunable.schema。 - 在
src/settings.ts补该厂商的可调类型,客户端SettingsTab.tsx按需要增加分区。 - 在
cordis.patch.yml补该厂商的默认配置(只写需要覆盖的字段,其余交给 schema 默认值)。 pnpm run build后按开发流程验证。
最小骨架:
// src/providers/acme.ts
// (z 来自 @deepseek-ai/schemastery;withCommonConfig / ProviderModule / ProviderAdapter
// 来自 providers/types.ts,此处省略 import 语句)
export const acme: ProviderModule<AcmeConfig, AcmeTunable, 'acme'> = {
id: 'acme',
displayName: 'Acme',
kind: 'balance', // 或 'quota'
config: withCommonConfig({
apiKeyEnv: z.string().default('ACME_API_KEY'),
baseURL: z.string().default('https://api.acme.example'),
// 如需设置页热更新:把可调字段与 tunable schema 共用一份定义
}),
// tunable / display 可选,缺省即没有设置页热更新与专属展示偏好
create: (ctx, config) => new AcmeAdapter(ctx, config),
}
class AcmeAdapter implements ProviderAdapter {
readonly id = 'acme'
readonly displayName = 'Acme'
readonly kind = 'balance' as const
async fetch(): Promise<ProviderSnapshot> {
// 取数 + 归一化;错误时返回 status: 'error' 的快照
}
}
开发
pnpm install
pnpm run build # 产出 lib/index.js(host ESM)与 lib/client.js(浏览器 loader 闭包)
pnpm run typecheck # tsc --noEmit(基于 npm 发布的 @deepseek-ai 类型)
pnpm run format # prettier 统一格式化(提交前执行;format:check 仅检查)
pnpm run smoke # 客户端 bundle 冒烟:mock 模块加载器 + mock ctx,无需浏览器
pnpm run smoke:host # host 冒烟:多厂商编排、模型切换联动、鉴权重试,无需 key
迭代循环:改 host 半 → pnpm run build → 重启 dsh web;改 client 半 → pnpm run build
→ 刷新页面。本地 node_modules 里的 @deepseek-ai/* 来自 npm 发布版本,若运行中的 dsh
版本接口有变化,请同步 peerDependencies 后重新 pnpm install。
已知限制
- 余额为异步结算,徽标展示的是近实时快照,面板标注原更新时间。
- 本地路由与 SSE 端点不带鉴权(dsh webServer 的设计如此);dsh web 默认绑定
127.0.0.1,若绑定0.0.0.0会把这些只读端点暴露到网络。 turn/end对空轮次(输入被拒等)也会发出,多一次无害的余额查询。- 模型切换没有“点击即触发”的持久事件:高亮点击即生效,数据在下一轮次消息时才刷新。
参考
License
MIT
Plugins relacionados
dsh-context
bowenliang123/dsh-context
deepseek-balance-whale-widget
meteornox/deepseek-balance-whale-widget
dsh-cost-meter
han-1413141/dsh-cost-meter
TokenLedger
zh667/tokenledger