中文EN

dsh-faremeter

usagenpmMIT

按 DeepSeek 官方价目显示每轮、每会话与每工作区的对话费用人民币金额,支持峰谷分时与 Search/Fetch 按次计费。

下载量 / Downloads
620

安装

dsh plugin --profile web add dsh-faremeter

沙箱测试

这个插件还没测过。提交测试 →

README

<div align="center">

dsh-faremeter — 给 AI 对话打表

token 按官方三档 + 峰谷实时计价;2026-11-01 起网页搜索/抓取按次计费(¥5/1000 次),一次不漏。每轮 · 每会话 · 每工作区,三处人民币金额。

简体中文 · [English](README_en.md)

<img src="assets/banner.png" alt="dsh-faremeter 宣传图:三个显示位与人民币金额" width="720">

</div>

三个显示位置:

位置 · 显示什么

每轮回答的操作行(token 用量胶囊右侧) · 这一轮花了多少

输入框底部 dock(官方 stats 胶囊旁) · 本会话累计 / 全部会话累计

侧边栏每个工作区行尾 · 该工作区(跨会话)累计

金额按 DeepSeek 官方 API 价格 计算,分两块口径:

① token 计费(按官方口径区分三种 token 与两类时段):

计费桶 · 取价档位

缓存命中输入(cacheReadTokens) · 缓存命中价

未命中输入(uncachedInputTokens) · 缓存未命中价

输出(outputTokens,已含 reasoning) · 输出价

峰谷:高峰时段 = 北京时间 周一至周五(不含中国法定节假日)9:00–12:00、14:00–18:00,高峰价 = 空闲价 × 2;其余时段(含周末、调休上班的周末、法定节假日全天)一律空闲价。

当前价目(CNY / 百万 token,[空闲, 高峰]):

模型 · 命中 · 未命中 · 输出

deepseek-flash · 0.02 / 0.04 · 1 / 2 · 4 / 8

deepseek-v4-pro · 0.15 / 0.30 · 4.5 / 9 · 13.5 / 27

② Search / Fetch 按次计费(官方公告 2026-10-25,北京时间 2026-11-01 00:00 起生效,之前的调用免费;不分峰谷):

API · 计费单位 · 价格

Search(web_search 服务端搜索) · 每 1,000 次成功请求 · 5 元

Fetch(web_fetch 服务端抓取) · 每 1,000 次成功请求 · 5 元

「一次成功请求」在日志里的判定:web_fetch 的 tool/result 无 isError/error 即一次;web_search 一次调用带 N 个子查询 = N 次请求(本机实测 35 次调用 / 59 子查询 = 59 条请求事件,严格对应)。生效线以请求发起时刻判定。

价表快照:token 价 2026-09-19 复核;Search/Fetch 价 2026-10-25(公告原文)。官方再次调价时,改 lib/client.js 与 lib/cost-core.mjs 两处的 FLASH_PRICE / PRO_PRICE / WEB_REQUEST_UNITS(两份实现由测试保持逐位一致)。

界面

每轮(token 用量旁边):
  复制  反馈  分支  消耗 1.6M tokens  ¥0.920  21:50
                                     └─ 本插件

输入框底部(官方 stats 胶囊旁):
  … 12 轮 · 3 步 · 42 tok/s   1.6M tokens · 缓存 92%   ¥3.84

侧边栏工作区:
  ▼ 价格显示插件                          ¥1.23
      session-9cc5451a…
  ▼ ssh插件                              ¥18.46
      session-3611dbc7…
  • 每轮胶囊高峰时段带 ▲ 角标;点开是完整明细(模型、时段、缓存命中率、三档单价、分项与合计;本轮有搜索/抓取时另有按次行)。
  • 底部累计胶囊点开显示:本会话 / 本工作区 / 全部会话 / 搜索与抓取分项 / 账本扫描状态。
  • 工作区金额用 pointer-events:none,不会拦截整行的折叠点击。
  • 卸载插件后 DOM 完全还原,不留残余节点。

三个数字分别从哪来

数字 · 数据来源 · 覆盖范围

每轮金额 · 客户端:useChat → turn-tail 节点的 tokenUsage · 当前已加载的轮次

本会话 / 全部 / 工作区 · 宿主:扫描 ~/.dsh/sessions 全部会话日志 · 包含安装插件之前的历史会话

宿主账本以会话日志文件为唯一事实源:DSH 实时落盘,所以文件内容就是最新真相;插件每 15 秒增量重扫(只重扫 mtime/size 变化的文件),首次全量扫描在启动 1.2 秒后异步分片进行(实测本机 52 个会话 / 约 30MB 压缩日志 → 1.8 秒)。

会话日志是「每行一条 JSON、每行单独压成一个 zstd 帧」的多帧格式,zstdDecompressSync 只解第一帧。lib/session-scan.mjs 移植了官方 dsh-session-persistence-jsonl 的帧扫描逻辑(纯 JS、不碰 Node 私有 API)来逐帧解压。

工作区归属:session 头事件里的 cwd;宿主再用 workspaceRegistry 服务把 workspaceId ↔ path 对上,下发 byWorkspaceId,客户端按 data-row-key="workspace:<id>" 直接匹配。

计费口径(与官方一致的细节)

  • 缓存命中单独取价:命中的输入按命中价,未命中的输入按未命中价,两者都各自乘量后相加——不是用平均价糊一遍。
  • cacheWriteTokens 不单独计价:DeepSeek 只有命中 / 未命中 / 输出三档,缓存写入的成本本来就在未命中输入里。照搬 Anthropic 的 cacheWrite × 1.25 会把费用算高。
  • reasoningTokens 不另计:DSH 的 outputTokens 已经包含推理 token。
  • 峰谷按该轮请求时刻判定(取该轮 ending 时间),并先换算到 UTC+8 再比较——不会因为宿主机时区不同而算错。
  • Search/Fetch 按成功请求次数计费(每次 ¥0.005,不分峰谷),带生效线闸门:以请求发起时刻与北京 2026-11-01 00:00 比较,之前的调用免费;失败请求(结果带 isError/error)与未出结果的调用不计。
  • Search 的「请求次数」= 子查询数:一次 web_search 调用的 queries 数组有多长就发几次请求(与宿主日志里 web/deepseek-search-llm-request 事件数实测一致);客户端看不到该事件,所以两边统一按子查询数计,请求事件数留作 live-ledger 的交叉核对。
  • 金额用整数定标累加:内部以 1e-8 元 为单位整数相加(tokens × 价格 × 100),只在展示时换算,避免浮点漂移导致「合计 ≠ 各项之和」。Search/Fetch 同样走整数定标(每次 500,000 units)。
  • 判不出的模型按 Flash 价估算,并在面板里明确写出提示,不假装精确。

安装

# 预览要做的改动(不落盘)
pwsh -File install-profile.ps1 -WhatIf

# 装进 desktop profile
pwsh -File install-profile.ps1

# 卸载
pwsh -File install-profile.ps1 -Uninstall

脚本会:备份 profile 的 package.json → 加一条 link: 依赖 → 把 dsh-faremeter 追加进 dsh.profile.bundles → 在 profile 的 node_modules 下建 junction。

装完必须完全退出并重开 DSH Desktop(关窗口不够,要退出进程),客户端 bundle 才会被编进 window.__DSH_BOOT__。

依赖的宿主形状

项 · 值

插槽 · conversation.chat.assistant-actions(list,session 作用域,order: 20)

条目 id · faremeter

数据来源 · slot 标准 props 的 useChat → turn-tail 节点的 data.tokenUsage / data.closing.time

注入服务 · 只有 slots

胶囊的落点:先渲染一个不可见锚点拿到自己在官方操作行里的位置,再从锚点向上找 [data-clock="end"](已完成轮次的操作行),取其最后一个子节点(装着用量胶囊与时钟的 span),用 ReactDOM.createPortal 把胶囊渲染到一个插在「用量胶囊之后、时钟之前」的容器里。

定位不到时不会消失,而是回落到操作行原位:如果 DOM 形状变了、或者这一行没有用量胶囊,胶囊就直接渲染在插槽自己的位置(复制按钮右侧)。这样「插件没生效」和「定位没匹配上」不会长得一模一样。

取数口径:snapshot.nodes 在真实宿主里是 MutableChatNodeStore(有 get(key) 与 values(),没有 forEach)。这一点踩过坑:早期版本用 forEach 遍历,结果静默取不到任何节点,胶囊永远不出现。现在 nodeListOf() 同时兼容 store / Map / 普通对象三种形状,并有专门的回归测试钉住。

打包分发

pwsh -File pack.ps1

产物在 dist\:

文件 · 用途

dsh-faremeter-<version>.tgz · npm 标准包,DSH 插件安装走这个。内容严格按 package.json 的 files 白名单,不含测试与打包脚本

dsh-faremeter-<version>.zip · 源码分发:解压即得完整插件目录,直接跑 install-profile.ps1 安装;额外带测试便于复核

脚本会先跑完四组测试再打包——测试不过就中止,不会产出带病产物。打包后还会做三件事:

1. 校验 tgz 条目清单(必需文件齐全、没混进测试/依赖/打包脚本);

2. 把 tgz 解包到临时目录真跑一次:加载 lib/index.js、调 apply()、断言路由注册成功且 apply 不抛错、客户端产物关键标记齐全;

3. 生成 zip 并打印 SHA256。

打包时把 npm 缓存钉在 .npm-cache\(而不是用户全局缓存),避免沙箱限制与污染。

排查

如果胶囊没出现,在浏览器控制台(Ctrl+Shift+I)手打下面这一行回车:

__DSH_FAREMETER__

会返回一个诊断对象:

字段 · 看什么

applies · 0 = 客户端插件根本没被应用(bundle 没加载)

entries · 为空 = 条目根本没被渲染;hasUseChat:false = 宿主没给 useChat;hasUsage:false = 没取到本轮用量

entries[].propKeys · slot 标准 props 的实际字段清单

placements · endInfo:false = 没找到「用量胶囊之后」的落点,此时胶囊会回落到操作行原位

notes[0].nodeStore · 宿主 snapshot.nodes 的实际能力(`hasVa

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:2,最后更新 2026-10-25

链接

GitHub · Homepage · npm

同类插件