aliensweety/dsh-usage-dock ↗★ 0
dsh-usage-dock
Per-session CNY cost pill in the composer dock: rides the shipped stats row and expands into the token buckets and both tariff bounds.
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:aliensweety/dsh-usage-dock说明文档
阅读完整 README ↗dsh-usage-dock
在输入框下方那排统计药丸(官方 Session 信息 + Token 用量)后面并排追加一颗只显示金额的药丸,样式与官方药丸一致、三粒作为一组居中:
[ Session 信息 ] [ Token 用量 ] [¥ 0.47]
点开是明细:未缓存输入 / 缓存读取 / 缓存写入 / 输出 / 总计 / 高峰价与空闲价两档费用 / 缓存命中率。
官方那排已经在显示 Session 与 Token 用量了,所以这颗药丸不再重复这些数字:收起态只有一个金额,其余信息放在 tooltip 与展开面板里。
费用估算口径
- 价格来源:DeepSeek 官方定价页(人民币/百万 tokens,高峰价)——
deepseek-flash输入未命中 ¥2、缓存命中 ¥0.04、输出 ¥8;deepseek-v4-pro未命中 ¥9、缓存命中 ¥0.30、输出 ¥27。空闲档一律为高峰价的一半。 - 模型匹配:读
modelSelection投影的lastUsed.model,id 含pro按 v4-pro 计价,其余按 flash 计价。 - 只对
deepseek-official路由计价:lastUsed.provider是别的路由时整颗药丸不渲染。用 DeepSeek 价目表去算 Claude/GPT 的 token 会得出一个"很确定的错数字",宁可沉默。 - 药丸上的金额:按查看时刻所处时段自动取高峰或空闲档;面板里两档始终并列展示,所以跨时段的会话其真实费用介于两者之间。
- 缓存写入不计价:官方价格表没有单独的缓存写入价(本机数据里 cacheWrite 也恒为 0),字段保留、默认 0。
价格与时段(已核对,截至 2026-09-12)
lib/client.js 里的 PRICING / isPeakNow() 与官方口径一致:
| 模型 | 档位 | 缓存命中 | 未命中 | 输出 |
|---|---|---|---|---|
deepseek-v4-pro | 高峰 | 0.30 | 9 | 27 |
deepseek-v4-pro | 空闲 | 0.15 | 4.5 | 13.5 |
deepseek-v4.1-flash(含 deepseek-flash) | 高峰 | 0.04 | 2 | 8 |
deepseek-v4.1-flash | 空闲 | 0.02 | 1 | 4 |
单位:元/百万 tokens。峰谷时段:北京时间工作日 9:00–12:00、14:00–18:00 为高峰,其余(含夜间与周末)为空闲、按高峰价的一半计。
关键点:V4 Pro 独立计费——它继续调用 V4 Pro 本身,不会路由到 V4.1 Flash(原定 2026-09-14 12:00 的路由计划已于 09-11 取消),所以两者的价目表不会互相套用。这也是本插件按 modelSelection.lastUsed.model 取价、而不是按"当前默认模型"取价的原因。
价格调整后无需改代码,在 Web 控制台执行(对所有已计价模型生效,均填高峰价):
localStorage.setItem('dsh-usage-dock.pricing', JSON.stringify({ miss: 2, hit: 0.04, out: 8, write: 0 }))
删除该 key 即恢复内置价格。
数据来源
只读 DSH 内置的会话投影 tokenUsage 与 modelSelection,不读会话日志文件、不发网络请求、不碰任何凭证。
tokenUsage 由 provider 上报的用量累加而成,整段会话一个值,带 seq 单调保护,所以它是权威值而非本地估算;它的线上视图是扁平四桶:
{ uncachedInputTokens, outputTokens, cacheReadTokens, cacheWriteTokens }
样式、位置与"明细放哪"
样式:与官方药丸逐条对齐——padding:1px 8px、border-radius:24px、gap:6px、--dsw-alias-label-tertiary 文字色与 --dsw-alias-interactive-bg-hover 悬停底色、font:inherit / line-height:inherit;宽屏带一颗 14px 图标,窄屏(≤640px)图标让位给一个 ¥ 字符,把宽度留给三个药丸。
位置:composer 下方那个 dock 是一个 column flex 容器(flex-direction:column; align-items:center),slot outlet 自己带 display:contents,所以第二个条目天然会另起一行;slot 契约里也没有"加入官方那一行"的入口(官方那颗 StatsPills 是自带排版的完整条目,也不声明子 slot)。
所以本插件用 ReactDOM.createPortal 把药丸直接渲染进官方那一排的 DOM 里(官方药丸的浮层也是用同一个 API):
- 官方那排是
display:flex; gap:12px; justify-content:center,药丸进去后自动拿到同样的 12px 间距、并和它们一起居中——不需要平移、不需要改官方任何元素、不需要测量像素; - 靠一个
display:none的宿主节点留在 outlet 里,只用来找那一排(data-composer-stats标记);每次提交都重新解析,composer 重挂载换了节点、或那一排消失时会自动跟上; - 退化行为:找不到那一排(或宿主没提供
react-dom)时,药丸退回"自己一行居中"的原状。 - 药丸带
flex:none:窄屏上被压缩的是官方那两粒(它们本来就会 ellipsis),本插件这一粒金额始终完整可读。
明细放在官方 token 用量卡里:点官方那粒 21.1M tok · Cache hit 99% 打开的卡片,本来就已经列出四个 token 桶;本插件把那两行费用(高峰价 / 空闲价)和一个估算说明追加进那张卡的同一个 ``:
- 那张卡的行是
dt/dd对,而它的样式是元素选择器(.xxx_details dt/.xxx_details dd{display:grid;…text-align:right}),所以追加进去的/自动拿到和官方行完全一致的排版与配色,不需要写任何上游类名; - 检测方式:那一排里最后一颗
button[aria-haspopup="dialog"]就是官方 token 用量药丸,它aria-expanded="true"时出现的div[role="dialog"]就是它自己的卡(官方一次只开一张卡);MutationObserver盯document.body的childList,卡片一出现就写入,卡片还开着时数值变化就地更新; - 点本插件这颗药丸 = 直接打开那张官方卡片(没有自己的浮层,所以窄屏不会再溢出);
- 写入失败(上游改了结构、宿主没给
react-dom、或那一排/那粒药丸不存在)时:药丸的金额照常显示,明细退回自带的兜底面板(该面板只在对齐到屏幕外时才翻转贴边,max-width也限制在视口内)。
安装