Skip to content

feat: add DeepSeek Token Usage v1.17.4 (reads scoped to DeepSeek by provider/model) - #88

Closed
Saydness wants to merge 2 commits into
BigPizzaV3:mainfrom
Saydness:add-deepseek-token-usage
Closed

Saydness wants to merge 2 commits into
BigPizzaV3:mainfrom
Saydness:add-deepseek-token-usage

Conversation

@Saydness

@Saydness Saydness commented Sep 11, 2026

Copy link
Copy Markdown

投稿内容

新增 Codex++ 用户脚本 DeepSeek Token Usage,用于统计 DeepSeek 模型在 Codex 里的 token 用量与费用。

本次改动(回应上一轮审查的两条意见)

1. 读取范围收紧为「按 provider/model 归属」

isLikelyApiUrl() 里去掉了 isLoopbackUrl()includes("/responses") 这类宽判定,改成按本次调用是否属于 DeepSeek 来判断:

读不读 条件
主机名里含 deepseek 的地址(例如 api.deepseek.com
路径是 /chat/completions/completions/beta/chat/completions并且本次请求体里点名了 deepseek 模型——本机中转、自建代理走的就是这个路径,靠模型名认归属
不读 任何主机上非 completions 路径的接口(例如 127.0.0.1:xxxx/api/status
不读 /responses(OpenAI Responses API)
不读 请求体里没有 deepseek 的 completions 调用(例如发往其它 provider 的请求)
不读 WebSocket 里从头到尾没出现过 deepseek 模型名的连接
不读 Codex 页面自身的接口

请求体只做一次「里面有没有 deepseek」的子串判断(最多扫 200 KB),不保存、不落盘、不上报;响应正文只用来提取模型名、token 数量、时间戳。

WebSocket 采用「首帧认出归属,这条连接的后续帧继续解析」:流式分片通常只有首帧带模型名,若逐帧判断会漏掉末尾那条带 usage 的帧;而一条从没出现 deepseek 的连接,一帧都不读。

另外说明一处与网络响应无关的采集:面板还会监听 Codex 页面自身发出的 postMessage 事件(含 codex-message-from-view),只从中取 token 用量、模型、时间戳三个字段。

2. 描述与产物版本对齐

上一轮描述写的是 1.13.0index.json 登记 1.16.1,版本对不上。这次描述、脚本头部 @version / VERSIONindex.json 统一为 1.17.4sha256 同步更新;index.jsonupdated_at 也一并更新(合并时若与其他 PR 冲突,以你的统一处理为准)。

功能

  • 逐条请求统计 token 用量:优先使用该次请求实际携带的模型名,按模型分别计费;
  • 内置 DeepSeek 官方 CNY 费率表,区分缓存命中 / 缓存未命中 / 输出,并按北京时间峰谷时段计价(周一至周五 09:00-12:00、14:00-18:00 为高峰);
  • 按天、按月查看用量与费用,图表柱和费用点支持鼠标悬浮查看该节点明细;
  • 面板可整体拖动,四边和四个角都能调整大小,位置与尺寸会被记住;
  • 可收成只显示 token 用量和费用的 mini 状态条;首次打开强制展示完整面板;
  • 账户余额(可选):面板自己查(填 Key 或读 Codex 配置里的 Key),只认接口返回的数值,不用本机用量推算;每日余额消耗按天记录;
  • 历史用量保存在本机 localStorage,重启 Codex 不会丢。

隐私

  • 不读取、不保存 API Key,不读取提示词或响应正文内容;
  • 只记录模型名、token 数量、费用、时间、来源等统计字段;
  • 代码中没有任何外部 http(s) 地址,不存在上传或遥测;
  • 不包含任何机器 IP、用户名、服务器地址或密钥。

与市场已有脚本的共存

已与 codex-token-usagecodex-daily-token-usagecodex-live-token-cost 对比:

  • 全局属性 __deepseekUsagePanel、存储键 __deepseekUsagePanelV1、DOM id 均未与上述脚本重名;
  • window.fetch / XMLHttpRequest / WebSocket 采用链式包装,保留并调用原实现,可与其他采集类脚本同时启用;
  • 顶栏按钮注入到 .ms-auto.flex.shrink-0.items-center(与 codex-daily-token-usage 同一容器),属于并排追加,不会覆盖对方节点。

校验方式

sha256 是对 scripts/deepseek-token-usage.js 原始字节计算的,可用下面命令复核(PowerShell):

(Get-FileHash .\scripts\deepseek-token-usage.js -Algorithm SHA256).Hash

DeepSeek-focused token usage and cost panel: per-request per-model pricing
from the official CNY rate table (peak/off-peak by Beijing time), daily and
monthly charts with hover tooltips, draggable/resizable panel, mini mode.
Collects only model name, token counts, cost and timestamps locally.
@BigPizzaV3

Copy link
Copy Markdown
Owner

审查结论:实现克制、功能完整,但读取范围过宽 + 描述与产物不一致,当前不合并

做得好的部分,这些是认真的:

  • 只观察不篡改——包装 fetchXMLHttpRequest.prototype.open/sendWebSocket 后读取响应体解析 token 数,请求与响应原样放行,不改写任何内容;
  • 包装函数都带 __deepseekUsageWrapped = VERSION 标记跳过重复包装,并保留原函数引用;
  • 源码注释明确写了「面板自己的 localStorage 不保存任何密钥」「用户刚填还没交给助手保存的 Key 只存在于页面内存,从不进 localStorage」,隐私边界交代清楚;
  • 费率表区分缓存命中/未命中/输出并按北京时间峰谷计价,细节到位。

不合并的两个原因

  1. 响应读取范围过宽isLikelyApiUrl() 的判定是 includes("deepseek") || isLoopbackUrl() || includes("/responses") || includes("/chat/completions") || includes("/completions")——其中 loopback 与 /responses 两条会把大量与 DeepSeek 无关的本地请求响应也纳入解析。用于本地统计这可以理解,但意味着不只 DeepSeek 的流量会经过这份解析代码。请把范围收紧到真正需要的判定条件(例如按实际 provider/model 归属过滤),并在 PR 描述里写明「会读取哪些请求的响应体、不读取哪些」,让用户知道自己让渡了什么。

  2. PR 描述与产物不一致。描述里写的是 version: 1.13.0,但 index.json 登记的是 1.16.1。请同步更新描述(或说明后续版本变更内容),否则审查和用户认知都会对不上产物。

补充一点:本 PR 没有更新 index.jsonupdated_at(仍是 2026-08-22),多个 PR 并行时这个字段容易冲突,合并时会统一处理,不作为你的问题。

收紧范围并同步描述后,欢迎重新提交。若你希望用户先自行安装,homepage 里已经指向了你的仓库。

@BigPizzaV3

Copy link
Copy Markdown
Owner

自上次审查结论(见上方 评论)以来,本 PR 没有新的提交,head 仍为 b23da79frelease: DeepSeek Token Usage v1.16.1)。

维持不合并的结论并关闭本 PR。两个原因仍未解决:

  1. 响应读取范围过宽isLikelyApiUrl()includes("deepseek") || isLoopbackUrl() || includes("/responses") || includes("/chat/completions") || includes("/completions") 判定,其中 loopback 与 /responses 会把大量与 DeepSeek 无关的本地请求响应也纳入解析。请收紧到真正需要的判定条件(例如按实际 provider/model 归属过滤),并在 PR 描述里说明「读取哪些、不读取哪些」。
  2. 描述与产物版本不一致:描述写 1.13.0index.json 与脚本头部是 1.16.1

这个功能本身有价值,不合并只是范围与描述问题。 修正上述两点后欢迎重新提交;在此期间脚本可以通过 homepage 指向的作者仓库分发。

「只观察不篡改」的实现方式、包装标记防重复、以及明确声明 API Key 只存在页面内存且不进 localStorage,这些处理都是正确的,感谢认真实现。

@BigPizzaV3 BigPizzaV3 closed this Sep 16, 2026
@Saydness Saydness changed the title feat: add DeepSeek Token Usage feat: add DeepSeek Token Usage v1.17.4 (reads scoped to DeepSeek by provider/model) Sep 17, 2026
@Saydness

Copy link
Copy Markdown
Author

按上一条审查意见改完了,因为这个分支被 force-push 过,GitHub 不允许重新打开本 PR(state cannot be changed. The add-deepseek-token-usage branch was force-pushed or recreated.),所以在同一分支上重新提交了一份:#92

两处问题的处理:

  1. 读取范围isLikelyApiUrl() 去掉了 isLoopbackUrl()includes("/responses"),改成按 provider/model 归属判断——主机名含 deepseek,或路径为 /chat/completions /completions /beta/chat/completions 且本次请求体里点名了 deepseek 模型才读;127.0.0.1 上的其它接口、/responses、发往其它 provider 的 completions、请求体里没提 deepseek 的流量一律不读。WebSocket 只解析「消息里出现过 deepseek 模型名」的连接(首帧认出归属后该连接后续帧继续解析,否则会漏掉流式末尾的 usage),其余连接一帧都不读。新 PR 描述里有完整的「读什么 / 不读什么」表格。
  2. 描述与产物版本:描述、脚本头部、index.json 统一为 1.17.4sha256 同步更新,updated_at 也一并更新。

本 PR 先留着做对照,不再需要的话可以直接关掉。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants