@kenz1117/dsh-ui-usage-billing 0.9.7 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -38,8 +38,9 @@
38
38
 
39
39
  ![Rates: model rate table (peak/off-peak split and live rate)](screenshots/5.png)
40
40
  - **Official vs third-party buckets**: the detail cost column is split by official DeepSeek direct / third-party relay ("official x / third y" when mixed); the Stats tab has an official/third-party summary card.
41
+ - **Relay-site attribution & quota**: usage is grouped by a provider's `baseURL` origin — multiple keys on the same relay station merge into one row, named by its domain. The Providers tab adds a "Relay sites" card (relay / direct / unknown-route states — an unknown route is one deleted or renamed in the current provider config, honestly labeled "cannot read" rather than mis-attributed as direct). Routes with a `baseURL` are auto-detected as New API (`/api/status`) or Sub2API (`/v1/usage`) to read their **balance and rolling quota windows**, labeled "no quota" when unreadable; the Zhipu GLM / Z.ai (CN region) wallet balance is now supported (read alongside the subscription plan). Project attribution prefers the workspace title for naming.
41
42
  - **Monthly budget + tier alerts**: a budget bar (on/off / amount / progress, ≥80% amber, over red pulse); notifies once per tier crossing 50/80/100%; a balance below the threshold (in CNY) alerts once a day.
42
- - **Subscription quota**: detects subscription providers in `llm-pi-ai` (Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / Xiaomi / Volcano…); those with a quota API show remaining % and reset time live, exhausted in red, no API shown as "not wired"; subscription-channel model cost is 0.
43
+ - **Subscription quota**: detects subscription providers in `llm-pi-ai` (Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / Xiaomi / Volcano…); those with a quota API show remaining % and reset time live, exhausted in red, no API shown as "not wired"; subscription-channel model cost is 0. **MiniMax note**: use the `minimax-token-plan-cn` provider id in MiniMax API for region `https://api.minimaxi.com`; the international route keeps `minimax` / `minimax-token-plan` against `https://www.minimaxi.com`. Override `baseUrl` per provider for proxies or staging.
43
44
 
44
45
  ![Providers: provider billing & subscriptions (balance, plan quota, model usage)](screenshots/3.png)
45
46
  - **Custom provider balance**: configure any HTTP endpoint for balance (`extract` supports constant / dot-path / add-subtract / divide, header `{{ENV}}` via the credentials seam); DeepSeek / Kimi / StepFun / SiliconFlow have built-in official balances, and the balance column estimates "≈N days" from the 7-day daily burn.
@@ -90,7 +91,7 @@ Browser Server (Node)
90
91
  └─ renders the dashboard
91
92
  ```
92
93
 
93
- - **Server** (`src/index.ts`): injects `webServer`, `sessionPersistence` and `credentials`, and registers `GET /api/billing/usage-stats`, `/api/billing/pricing`, `/api/billing/balance`. The aggregator caches folded results per session: each LLM call is attributed to the model of its preceding `request/header`, tokens split into cache-hit / cache-miss buckets, dates bucketed by the local timezone; a log file with unchanged mtime+size reuses its cached fold, only written sessions are re-folded, and the whole document has a 5s TTL to coalesce heavy polling. Aggregation logic lives in `src/aggregate.ts`.
94
+ - **Server** (`src/index.ts`): injects `webServer`, `sessionPersistence` and `credentials`, and registers `GET /api/billing/usage-stats`, `/api/billing/pricing`, `/api/billing/balance`, `/api/billing/subscriptions`, `/api/billing/relay-quotas`. The aggregator caches folded results per session: each LLM call is attributed to the model of its preceding `request/header`, tokens split into cache-hit / cache-miss buckets, dates bucketed by the local timezone; a log file with unchanged mtime+size reuses its cached fold, only written sessions are re-folded, and the whole document has a 5s TTL to coalesce heavy polling. Aggregation logic lives in `src/aggregate.ts`.
94
95
  - **Browser** (`src/client/`): requests the endpoints above to render the dashboard and probes each provider connection via `llm.models`. Until real data arrives it shows an all-zero empty snapshot, never fabricated samples.
95
96
 
96
97
  ## Theme collaboration
@@ -138,7 +139,7 @@ To add a model: append an entry to `MODEL_CATALOG` and map its real id in `MODEL
138
139
 
139
140
  ## HTTP API
140
141
 
141
- The public HTTP endpoints and field definitions are documented in source: `GET /api/billing/pricing`, `/api/billing/balance`, `/api/billing/usage-stats` (see `src/index.ts`, `src/aggregate.ts`).
142
+ The public HTTP endpoints and field definitions are documented in source: `GET /api/billing/pricing`, `/api/billing/balance`, `/api/billing/usage-stats`, `/api/billing/subscriptions`, `/api/billing/relay-quotas` (see `src/index.ts`, `src/aggregate.ts`, `src/relay.ts`). The `usage-stats` payload's `bySite` field is the relay-attributed usage distribution (`site:<origin>` / `direct:<provider>` / `unknown`).
142
143
 
143
144
  ## Configuration
144
145
 
@@ -177,7 +178,8 @@ None. This plugin is a pure UI surface: it registers no tools, injects no system
177
178
 
178
179
  ## Known Limitations and Deferred Work
179
180
 
180
- - **Balance queries cover DeepSeek / Moonshot (Kimi) / StepFun**: these three use a standard Bearer API key. Other providers expose no public balance API or need non-Bearer auth (Xiaomi MiMo via console Cookie, SenseTime via AccessKey signing, MiniMax/Doubao via quota or AK/SK), so they currently show "not configured"; the extension point is `src/balance.ts` (add a querier per provider balance API).
181
+ - **Balance queries cover DeepSeek / Moonshot (Kimi) / StepFun / SiliconFlow / xAI / Zhipu GLM (Z.ai CN region)**: these use a standard Bearer API key. Other providers expose no public balance API or need non-Bearer auth (Xiaomi MiMo via console Cookie, SenseTime via AccessKey signing, MiniMax/Doubao via quota or AK/SK), so they currently show "not configured"; the extension point is `src/balance.ts` (add a querier per provider balance API).
182
+ - **Relay quota depends on upstream private schemas**: New API / Sub2API interface fields are not public, so an unreadable station is labeled "no quota" rather than fabricating an amount; if a station's response fields differ, extend the parsers in `src/relay.ts`. An "unknown route" means that route no longer exists in the current provider config (renamed / deleted); historical call data is not lost — re-adding the same-named route restores attribution automatically.
181
183
  - **Overspend notifications rely on the browser Notification API**: when permission is denied or the platform lacks support, only the in-UI red-pulse fallback remains — no host-level notification channel; notifications are capped at once per day.
182
184
  - **Session rows are not navigable**: clicking a session row does not open that session (cross-plugin navigation needs a host session-selection channel); sessions are capped at 100 rows and the panel shows the top 20.
183
185
  - **Cost is a catalog estimate**: models without published per-token pricing (iFlytek, SenseTime, Xiaomi) use estimates (feature-list footnote ¹); official billing is authoritative.
package/README.md CHANGED
@@ -38,12 +38,13 @@
38
38
 
39
39
  ![费率:模型单价表(峰谷分时与实时汇率)](screenshots/5.png)
40
40
  - **官方 vs 三方分桶**:明细费用列按官方 DeepSeek 直连 / 第三方中转分解(混合时「官 x / 三 y」),统计 Tab 有「官方/三方」汇总卡。
41
+ - **中转站归组与额度**:按 provider 的 `baseURL` 归一化 origin 归组——同一中转站的多把 key 合并成一行,站名即域名;明细 Tab 新增「中转站分布」卡(中转站 / 直连 / 未知路由三态,未知路由 = 配置里已删 / 改名的路由,诚实标注「读不到」而非误归直连)。对配了 `baseURL` 的路由自动识别 New API 系(`/api/status`)与 Sub2API(`/v1/usage`)的**余额与滚动额度窗口**,读不出标「未读出额度」;智谱 GLM / Z.ai 国内域钱包余额已接入(与订阅套餐双读)。项目归属优先用工作区标题命名。
41
42
  - **月度预算 + 分档提醒**:预算条(开关 / 金额 / 进度,≥80% 琥珀、超支红脉);跨 50 / 80 / 100% 各提醒一次;余额折算 CNY 低于阈值每天提醒一次。
42
- - **订阅套餐额度**:识别 `llm-pi-ai` 里的订阅类 provider(Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / 小米 / 火山…),有额度 API 的实时显示剩余%与重置时间、用尽标红,无 API 标「未接入」;订阅通道模型费用记 0。档位月费与周期额度口径由内置知识库自动识别(如 OpenCode Go $10/月 + 周 $30 额度),有档位知识的标「自动识别」。
43
+ - **订阅套餐额度**:识别 `llm-pi-ai` 里的订阅类 provider(Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / 小米 / 火山…),有额度 API 的实时显示剩余%与重置时间、用尽标红,无 API 标「未接入」;订阅通道模型费用记 0。档位月费与周期额度口径由内置知识库自动识别(如 OpenCode Go $10/月 + 周 $30 额度),有档位知识的标「自动识别」。**MiniMax 用户注意**:在国内开发者环境请使用 `minimax-token-plan-cn` provider id,自动对接 `https://api.minimaxi.com`;国际保留 `minimax` / `minimax-token-plan`,默认 `https://www.minimaxi.com`。需要自配中转或 staging 时可在该 provider 设置里覆盖 `baseUrl`。
43
44
 
44
45
  ![明细:厂商计费与订阅(余额、套餐额度、模型用量)](screenshots/3.png)
45
46
  - **自定义 Provider 余额**:配置任意 HTTP 端点查余额(`extract` 支持常量 / 点路径 / add-subtract / divide,请求头 `{{ENV}}` 经凭据 seam);DeepSeek / Kimi / 阶跃星辰 / 硅基流动内置官方余额,余额列按近 7 天日均折算「约可撑 N 天」。
46
- - **真实用量聚合**:服务端从会话日志实时聚合(增量缓存只重算写过的会话),单会话损坏容错、快照落盘回退;内置 `usage_stats` 工具可让模型自查今天 / 本月花费(**默认关闭**,可在「设置」Tab 一键开关,重启应用后生效)。
47
+ - **真实用量聚合**:服务端从会话日志实时聚合(增量缓存只重算写过的会话),单会话损坏容错、快照落盘回退;`usage_stats` 工具让模型自查今天 / 本月花费。
47
48
  - **多语种 + 双币种**:¥ / $ 切换随币种双语(USD→英文、CNY→中文,仅本插件生效);费率表按所选币种换算。
48
49
  - **模型健康 + 未收录标注**:厂商接入状态圆点(绿 / 红 / 灰);模型 id 不在目录时标「未收录」按兜底价估算、厂商自动推断(如 `mi-mimo-2.5` → 小米);估算价模型标注「估算价」。
49
50
  - **会话明细 + 成本突增 + 热力图**:按会话费用倒序(标题 / 项目 / 调用 / 费用 / 最后活跃);每轮费用柱状图(最近 40 轮、金额贴柱顶、峰谷背景分带、超 2 倍红标归因);月 / 年日历热力图(5 档色阶、悬停明细;年视图近 52 周、GitHub 风格),头部显示活跃天数 / 连续使用天数。
@@ -53,7 +54,6 @@
53
54
  ![趋势:每日费用趋势、每轮费用与峰谷时段占比](screenshots/2.png)
54
55
 
55
56
  - **数据导出 + 离线自包含**:统计 Tab 导出按日 / 按会话 CSV 与全量 JSON;无图表库、无外部 CDN、纯设计令牌。
56
- - **系统稳定性与可靠性**:官方接口结构偏移自动降级告警(`invalid` 与网络不可达区分);余额 / 订阅 / 定价三类上游请求带统一超时预算、指数退避重试与每平台熔断冷却,避免瞬时故障反复打满轮询;统计快照写前 `.bak` 备份、损坏自动回退;会话日志读取前后校验变更避免半行误读;鉴权失败按 provider 分类冷却告警;每会话折叠缓存按 LRU 设上限,长期运行内存平稳。
57
57
  - **插件信息卡**:设置 Tab 常驻「关于」卡——插件名、描述、作者(可跳 GitHub)、源码仓库、npm、许可证 MIT、版本号(服务端读自包 `package.json`,单一来源,发布自动正确)。
58
58
 
59
59
  ![统计:导出、费用构成、工作区与会话明细](screenshots/4.png)
@@ -93,7 +93,7 @@ npm install @kenz1117/dsh-ui-usage-billing
93
93
  └─ 渲染仪表盘
94
94
  ```
95
95
 
96
- - **服务端**(`src/index.ts`):注入 `webServer`、`sessionPersistence` 与 `credentials`,注册 `GET /api/billing/usage-stats`、`/api/billing/pricing`、`/api/billing/balance`。聚合器按会话缓存折叠结果:一次 LLM 调用归属到其前置 `request/header` 记录的模型,token 拆分到缓存命中 / 未命中桶,日期按本机时区归天;日志文件 mtime+size 不变则直接复用缓存,只有写过的会话重新折叠,整份文档另有 5 秒 TTL 合并密集轮询。聚合逻辑见 `src/aggregate.ts`。
96
+ - **服务端**(`src/index.ts`):注入 `webServer`、`sessionPersistence` 与 `credentials`,注册 `GET /api/billing/usage-stats`、`/api/billing/pricing`、`/api/billing/balance`、`/api/billing/subscriptions`、`/api/billing/relay-quotas`。聚合器按会话缓存折叠结果:一次 LLM 调用归属到其前置 `request/header` 记录的模型,token 拆分到缓存命中 / 未命中桶,日期按本机时区归天;日志文件 mtime+size 不变则直接复用缓存,只有写过的会话重新折叠,整份文档另有 5 秒 TTL 合并密集轮询。聚合逻辑见 `src/aggregate.ts`。
97
97
  - **浏览器端**(`src/client/`):请求上述接口渲染仪表盘,通过 `llm.models` 探测各厂商连接状态。真实数据到达前显示全零空快照,不展示伪造样本。
98
98
 
99
99
  ## 主题协作
@@ -141,7 +141,7 @@ cost(CNY)= (missInput × p_input + cacheHit × p_cacheHit + output × p_outp
141
141
 
142
142
  ## HTTP API
143
143
 
144
- 对外 HTTP 接口与字段定义详见源码:`GET /api/billing/pricing`、`/api/billing/balance`、`/api/billing/usage-stats`(见 `src/index.ts`、`src/aggregate.ts`)。
144
+ 对外 HTTP 接口与字段定义详见源码:`GET /api/billing/pricing`、`/api/billing/balance`、`/api/billing/usage-stats`、`/api/billing/subscriptions`、`/api/billing/relay-quotas`(见 `src/index.ts`、`src/aggregate.ts`、`src/relay.ts`)。其中 `usage-stats` 返回的 `bySite` 字段为按中转站归组后的用量分布(`site:<origin>` / `direct:<provider>` / `unknown`)。
145
145
 
146
146
  ## 配置
147
147
 
@@ -180,7 +180,8 @@ npm publish --access public
180
180
 
181
181
  ## Known Limitations and Deferred Work
182
182
 
183
- - **余额查询已接入 DeepSeek / 月之暗面(Kimi)/ 阶跃星辰(StepFun)**:这三家用标准 Bearer API key 即可查询。其余厂商因无公开余额接口或需非 Bearer 鉴权(小米 MiMo 走控制台 Cookie、商汤走 AccessKey 签名、MiniMax/字节豆包走额度制或 AK/SK),暂显示「未配置」;扩展点在 `src/balance.ts`(按厂商余额 API 增加查询器)。
183
+ - **余额查询已接入 DeepSeek / 月之暗面(Kimi)/ 阶跃星辰(StepFun)/ 硅基流动 / xAI / 智谱 GLM(Z.ai 国内域)**:这些用标准 Bearer API key 即可查询。其余厂商因无公开余额接口或需非 Bearer 鉴权(小米 MiMo 走控制台 Cookie、商汤走 AccessKey 签名、MiniMax/字节豆包走额度制或 AK/SK),暂显示「未配置」;扩展点在 `src/balance.ts`(按厂商余额 API 增加查询器)。
184
+ - **中转站额度依赖上游私有 schema**:New API / Sub2API 的接口字段未公开,读不出时标「未读出额度」而非臆造金额;若某中转站响应字段不同,需按 `src/relay.ts` 的解析器扩展。未知路由表示该路由在当前 provider 配置里已不存在(改过名 / 删除过),历史调用数据未丢,重新配置同名路由即可自动归位。
184
185
  - **超支通知依赖浏览器 Notification**:权限被拒绝或平台不支持时只有界面红色脉冲兜底,没有宿主级通知通道;通知上限为每天一次。
185
186
  - **会话明细不可跳转**:点击会话行不会打开对应会话(跨插件导航需要宿主会话选择通道);会话数封顶 100 行、面板只显示前 20 行。
186
187
  - **费用为目录价估算**:讯飞 / 商汤 / 小米等未公布按量单价的模型使用估算价(特性表脚注 ¹),正式定价以厂商账单为准。