DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

O789Real /

O789Real/dsh-usage-cost

Verified

DSH 插件:在自带「用量」弹窗里把每个 token 环节折算成金额显示在 token 数字右边(DeepSeek 官方价目表 + 峰谷价,口径与 dsh-whale-widget 同源)

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@acc0a5cc
图片

dsh-usage-cost

在 DSH 自带「用量」弹窗里,把每一行 token 折算成金额,显示在 token 数字的右边,并在末尾追加一行合计。

Show the money next to the tokens in DSH's built-in usage dialogs. Prices follow DeepSeek's official CNY price list and its peak/off-peak schedule, decided by when that turn actually ran — not by when you open the dialog.

本轮用量                                        888,131 tok
─────────────────────────────────────────────────────────────
提供方 / 模型              deepseek-account/deepseek-flash
缓存命中                                            99.97%
未缓存输入                          296 tok  ¥0.000592
缓存读取                        886,912 tok  ¥0.0355
缓存写入                              0 tok  ¥0.00
输出                                923 tok  ¥0.007384
本轮费用                                    ¥0.0435(高峰价)

金额按这一轮发生的那一刻的峰谷价算,不是按你查看的那一刻 —— 高峰跑的轮次,晚上再点开看仍是高峰价。

  • 覆盖两个用量弹窗:每条回答下面那颗「用量 xx」胶囊(本轮用量)、以及输入框下方那颗会话级胶囊(Token 用量)。
  • 所有会话自动生效——它是全局界面插件,不需要逐会话开启,也没有任何按钮要按。
  • 金额口径与右下角小鲸鱼挂件 dsh-whale-widget 完全同源(DeepSeek 官方价目表 + 峰谷价),两处数字能对上。
  • 在 DSH 0.2.0-rc.2(桌面端 / Web)上开发与验证;只用 Node 内置模块,无运行时依赖。

一、安装 / 更新 / 卸载

给使用者:一行命令(推荐)

dsh plugin --profile desktop add dsh-usage-cost

--profile 换成你自己的 profile 名(桌面端一般是 desktop,纯 Web 部署常见 web)。 也可以直接在 DSH 的 设置 → 插件 里安装。

本地开发时用 link: 指向源码目录:

dsh plugin --profile desktop add link:/绝对路径/dsh-usage-cost

维护者:发包到 npm 的完整步骤见文末「发布到 npm」。

不装 CLI / 想手工控制:用脚本

# 安装或更新(幂等,可反复执行)
powershell -ExecutionPolicy Bypass -File .\install.ps1

# 卸载(去掉 bundle 声明 + 删包目录)
powershell -ExecutionPolicy Bypass -File .\uninstall.ps1

默认装到 E:\deepseekharness\.dsh\profiles\desktop;换 profile 就加 -ProfileDir "<路径>"。

装完要让它生效

你的界面是 怎么做
桌面端应用窗口 完全退出并重开 DeepSeek Harness。桌面壳的 index.html 是安装包里的静态文件,注入表在宿主启动时一次性收集,没有热刷新路径。
浏览器打开 http://127.0.0.1:<port>/ 刷新页面(F5)即可。

只改 assets/usage-cost.js(浏览器半)时不需要重启:宿主按 mtime 重读该文件,刷新页面就生效。 改 lib/index.js(宿主半)需要重启。


二、钱是怎么算出来的

单价单位 元 / 百万 token,[空闲价, 高峰价]:

模型 缓存命中(缓存读取) 缓存未命中(未缓存输入) 输出
deepseek-flash(含旧名 deepseek-v4-flash、…-vision-exp) 0.02 / 0.04 1 / 2 4 / 8
deepseek-v4-pro 0.15 / 0.30 4.5 / 9.0 13.5 / 27.0
  • 峰谷:北京时间周一至周五(不含法定节假日)9:00–12:00、14:00–18:00 为高峰;其余时段——含周末、调休上班的周末、法定节假日全天——按空闲价。高峰价 = 空闲价 × 2。
  • 每行金额 = 该行 token ÷ 1e6 × 该环节单价;合计 = 四行金额之和。
  • 峰谷按「这一轮发生的那一刻」判,不是「你点开弹窗的那一刻」:「本轮用量」弹窗会顺着打开中的胶囊回溯到 [data-turn-tail],读那一轮自己的时钟(官方动作行末尾的 HH:mm / M月D日 HH:mm / Y年M月D日 HH:mm)来定峰谷。所以高峰时段跑的一轮,晚上谷时再点开看,显示的仍是高峰价,金额不会因为「什么时候看」而变;反过来也一样。合计行右侧会标出这一轮按的是哪个价((高峰价) / (谷价)),鼠标悬停能看到判定依据。
  • 「Token 用量」那颗会话级胶囊的合计跨多轮、归不到单一时段,只能按当前时段单价估算,括注会写明 (按当前时段价)——看到这个括注就说明它不是逐轮回溯的结果。
  • 时钟读不到时(异常渲染等)自动退回「现在」,回执里 refSource 记为 now。
  • 一轮若正好横跨切换点(例如 11:55 开始、12:05 结束),整轮按该轮结束时刻的价算——与小鲸鱼挂件「每轮消耗」的口径一致。
  • 三个 token 桶是互不重叠的(DSH 的 未缓存输入 / 缓存读取 / 缓存写入 直接相加就是计费输入),所以不会重复计费。
  • 「缓存写入」按未命中价计。DeepSeek 的 API 不单独上报这一桶(实测恒为 0),所以对 DeepSeek 而言与挂件口径完全一致。

改价

价目表在两处,官方调价时都要改:

位置 作用
assets/usage-cost.js 顶部 @pricing-core 标记之间 浏览器半的内置价目表(离线/兜底用)
<DSH_HOME>/usage-cost-pricing.json(可选,自己新建) 运行时覆盖,不用重启也不用刷新,页面每次打开弹窗都会用到最新值

覆盖文件长这样(只写要改的部分即可):

{
  "currency": "¥",
  "models": {
    "deepseek-flash": { "hit": [0.02, 0.04], "miss": [1, 2], "out": [4, 8] },
    "my-gateway-model": { "hit": [0.1, 0.2], "miss": [2, 4], "out": [8, 16] }
  },
  "peakHours": [[9, 12], [14, 18]],
  "holidays": { "2027-01-01": 1 }
}

同步提醒:小鲸鱼挂件的同名单价在 dsh-whale-widget/lib/index.js 的 PRICING / BASE_PRICE / PRO_PRICE; 每年 11 月国务院发布次年放假安排后,记得给 HOLIDAY_VALLEY 补下一年的日期(两处都要)。


三、实现方式(为什么不碰官方代码)

插件是标准的 DSH bundle 包,分两半:

文件 角色
lib/index.js 宿主半:注册静态路由 + 往页面注入一行加载脚本。不读会话、不记账、不碰模型请求。
assets/usage-cost.js 浏览器半:价目表 / 峰谷 / 金额换算 / 弹窗标注 / 回执。经典脚本(不是 ES 模块)。
cordis.patch.yml bundle 挂载声明。

浏览器半怎么进页面(两条通道并存,自带幂等守卫):

  1. webserver/index-inject 结构化行 —— 桌面端唯一通道。行是内联脚本,自己建 <script src="/dsh-usage-cost/client.js"> 并吞掉 onerror,所以路由不在时也只是静默失败,绝不会让界面起不来。
  2. webServer.tapIndex —— 浏览器访问 http://127.0.0.1:<port>/ 时的通道。

标注只在官方已有的 DOM 上追加自己的节点,不替换、不包装、不改官方渲染代码:

  • 每行金额:往官方 <dd>(内容是 1,036 tok)里追加 <span data-dsh-usage-cost-role="uncachedInput">¥0.0006</span>;
  • 合计:往官方 <dl> 末尾追加一对 <dt>本轮费用</dt><dd>¥0.0435<span>(高峰价)</span></dd>;
  • 峰谷时刻:从「打开中的胶囊 → 所在 [data-turn-tail] → 该轮时钟」读出,不依赖任何宿主数据;
  • 定位靠官方锚点 [data-turn-usage-details] / [data-session-stats-usage];锚点没了会退化成「按标签文字反查 dl」;
  • MutationObserver 事件驱动 + 1.5s 轮询兜底:官方组件重渲染把我注入的节点删掉时,下一次扫描就补回来,且重复扫描不会叠加;
  • 读不出 token 数的行(例如 —)保持原样——宁可不标,也不标错;
  • 全程 try/catch:插件自身出问题只留一条回执,不会把界面带崩。

四、自检与排障

入口 看什么
http://127.0.0.1:19387/dsh-usage-cost/health 宿主半是否活着、路由是否注册、页面来取过脚本没有(clientJsServed)
http://127.0.0.1:19387/dsh-usage-cost/pricing.json 当前生效的价目表(含覆盖文件)
http://127.0.0.1:19387/dsh-usage-cost/report 页面回执:页面地址、DOM 普查(几个弹窗/几颗胶囊)、每行识别到的 token 与金额
<DSH_HOME>/usage-cost-host.log 宿主半落盘日志(模块加载 / apply / 注入行 / 路由注册)
<DSH_HOME>/usage-cost-report.jsonl 页面回执的落盘副本(同 /report,便于事后翻)

界面里没出现金额时,按顺序看这三处:

  1. /dsh-usage-cost/health 是否 200 → 不是:宿主半没加载(bundle 没进 dsh.profile.bundles,或者没重启)。
  2. clientJsServed 是否 > 0 → 是 0:页面还没拿到加载脚本(桌面端要重启应用;浏览器要刷新页面)。
  3. /dsh-usage-cost/report 里的 census → 若 turnTails: 0 而界面上明明有对话,说明脚本跑在了别的文档里; 若 turnPanels: 0,说明打开弹窗那一刻没扫到锚点(回执里会带 via / unknown 标签,直接就能看出是哪种情况)。

离线自检(不需要浏览器、不需要 DSH、零依赖):

npm test                        # 三个探针一起跑(CI 也是这条)
node tools/probe-syntax.mjs     # 经典脚本契约(顶层 export/import 会让整页起不来)
node tools/probe-pricing.mjs    # 价目表 / 峰谷 / token 文本解析 / 金额格式
node tools/probe-decorate.mjs   # 假 DOM 里的标注行为(中英 locale、峰谷按哪一刻、重复扫描、重渲染自愈、文字兜底、回执)

tools/mini-dom.mjs 是这些探针用的极简 DOM 夹具;tools/probe-session-turn.mjs 可以从 DSH 会话日志里 按轮次汇总真实 usage,用来跟界面上的数字对账:

node tools/probe-session-turn.mjs <解压后的 session.jsonl> [目标总 token]

五、已知边界

  • 峰谷按「这一轮自己的时间」判(见上)。会话级合计跨多轮,只能按当前时段估算,界面已标明。
  • 只认中文与英文两套官方 locale 的行标签;别的语言会退化成“按标签文字反查”的兜底路径,可能标不出来(回执里会记录没认出来的标签)。
  • 官方若改掉 data-turn-usage-details / data-session-stats-usage 这两个属性名,仍能靠文字兜底工作;改掉 dt/dd 结构、或把动作行末尾的时钟(_timeEnd)去掉,才会失效(时钟没了只是退回按“现在”定价,不影响其它功能)。
  • 金额是本地估算,不是账单;以官方账单为准。小鲸鱼挂件的「余额观测」才是真实消费的那一路数。

六、文件一览

文件 作用
lib/index.js 宿主半(路由 + 注入行 + 落盘日志)
assets/usage-cost.js 浏览器半(价目表 + 峰谷 + 标注 + 回执)
cordis.patch.yml bundle 挂载声明
install.ps1 / uninstall.ps1 / verify.ps1 手工安装 / 卸载 / 装完自检(幂等,带备份)
tools/mini-dom.mjs 离线探针用的极简 DOM 夹具
tools/probe-*.mjs 离线探针(打包契约 / 价格 / 标注 / 会话对账)
.github/workflows/ci.yml 推送即跑 npm test(Node 20 / 22)

七、维护要点

  • 官方调价 → 改 assets/usage-cost.js 顶部 @pricing-core 之间的 PRICING, 并同步 dsh-whale-widget/lib/index.js 里的同名常量(两处口径要一直对得上)。
  • 每年 11 月国务院发布次年放假安排后 → 给 HOLIDAY_VALLEY 补下一年的日期。
  • 官方改了弹窗 DOM → 先看 /dsh-usage-cost/report 里的 census 与 unknown 字段, 再决定是补锚点、补标签字典,还是修结构识别。
  • 改完先 npm test;改浏览器半只需刷新页面,改宿主半要重启 DSH。

八、让插件被找到(发布相关)

官方在 CONTRIBUTING.zh.md 里的说法是:

创建令你感兴趣的插件,并分享给其他人: 为你的 GitHub 项目添加 dsh-plugin 话题,让其他人更容易找到你的插件。

社区插件目录(如 dsh-plugin-shop、dsh-m) 的抓取规则是每日构建时扫描:

来源 条件
npm 包 keywords 里含 dsh-plugin 或 deepseek-harness
GitHub 仓库 仓库 topic 含这两个词之一,且根目录 package.json 有 name 与 dsh.bundle

两种来源都不需要向任何项目提交申请。本仓库因此同时具备:

  • package.json 的 keywords:dsh / dsh-plugin / deepseek-harness / …
  • GitHub 仓库 topics:dsh-plugin、deepseek-harness、dsh、deepseek、cost、pricing

另外可选的 dsh.catalog(DSH 自己不读,是目录用的,已验证加了不影响加载)用来控制货架上的展示:

"dsh": {
  "bundle": { "patch": "./cordis.patch.yml" },
  "catalog": {
    "category": "ui",
    "summary": { "en": "…", "zh": "…" },
    "capabilities": ["webServer", "fs"]
  },
  "compatibility": { "dsh": ">=0.2.0-0 <0.3.0-0", "profiles": ["web"] }
}
  • category 取值:tool / provider / ui / workflow / integration / theme / other;不写就由目录自动归类。
  • summary.en 与 summary.zh 必须同时给(各 ≤200 字)。
  • capabilities 是自述、不被强制:DSH 不隔离插件,这个字段只是告诉别人插件碰了什么。 本插件只用到 webServer(注册静态路由)与 fs(读自己的资源、往 DSH_HOME 写自己的日志), 不读会话、不碰凭据、不参与模型请求。
  • compatibility.dsh 写的是经过验证的范围(开发与验证于 DSH 0.2.0-rc.2); 写 >=0.2.0-0 才能把 0.2.0-rc.N 这类预发布算进来,<0.3.0-0 才能挡住下一行的预发布。

只发 GitHub、不发 npm 也能被目录收录:仓库有 topic + 根 package.json 含 name 与 dsh.bundle 即可 (目录会把默认分支的某个 commit 固定为版本)。若要走 npm,npm publish 后次日的构建会收录。

九、发布到 npm(维护者用)

发到 npm 之后,别人才能一行装:dsh plugin --profile <profile> add dsh-usage-cost。

# 0) 只需要做一次:到 https://www.npmjs.com/signup 注册账号,并验证邮箱;
#    强烈建议顺手开启 2FA(npm 对发布操作会要一次性验证码)
#    账号名建议与 GitHub 保持一致,方便别人认作者

# 1) 登录(在**你自己的终端**里跑,会走浏览器或要用户名/密码/验证码)
npm login
npm whoami                       # 打出用户名就说明登录成功了

# 2) 发布(在插件目录里跑)
cd <插件目录>
npm publish                      # 若开了 2FA,会提示输入一次性验证码:npm publish --otp=123456

# 3) 验证
npm view dsh-usage-cost version  # 能打出 0.2.0 就成了

之后每次发新版:改完代码 → 改 CHANGELOG.md → npm version patch(自动改版本号并打 git tag) → git push --follow-tags → npm publish。

几个必须知道的规矩:

  • 同一个版本号只能发一次,改任何东西都要升版本号(npm version patch|minor|major)。
  • 发布基本不可逆:72 小时内可以 npm unpublish,但同名同版本永久作废、且这个名字会被冻结一段时间。所以第一次发布前先把 README 和 files 看一遍。
  • 包里只有 files 列出的那几个文件(lib / assets / cordis.patch.yml / README.md / CHANGELOG.md / LICENSE,约 23 kB)——探针、脚本、.git 都不会上传。
  • npm test 已经挂在 prepublishOnly 上:探针不过就发不出去。
  • pnpm 11 默认对新发布的包有冷却期,别人可能要显式写 dsh-usage-cost@0.2.0 才装得到最新版;几天后自动消失。

MIT.

—/ 5

No ratings yet

Verified DSH bundle

Commit acc0a5ccbc96

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout