Skip to content
dsh.fish
Bundle

dsh-billing-tui

DeepSeek Harness 峰谷计费插件:实时统计 token 用量,按 DeepSeek V4 峰谷定价计算费用,生成 ASCII 账单小票,支持 TUI 状态行与 /billing 命令

Source
Ethanz11-creat
stars
2 stars
License
MIT
Updated
Updated 4 days ago

Readme

# dsh-billing-tui

[![npm](https://img.shields.io/npm/v/dsh-billing-tui?logo=npm)](https://www.npmjs.com/package/dsh-billing-tui)
[![license](https://img.shields.io/github/license/Ethanz11-creat/dsh-billing-tui)](https://github.com/Ethanz11-creat/dsh-billing-tui/blob/main/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/Ethanz11-creat/dsh-billing-tui?style=social)](https://github.com/Ethanz11-creat/dsh-billing-tui)

DeepSeek Harness (DSH) 峰谷计费插件 —— 实时监听会话 token 用量、按 DeepSeek 官方峰谷定价计算费用、生成鲸鱼 ASCII 账单小票,并在 TUI 状态行实时显示费用。

专为 [dsh][] (DeepSeek Harness) 及其 TUI 终端界面设计,同时兼容 Web UI。安装后即可在对话流里用 `/billing` 打印一张完整的收银台风格账单。

[dsh]: https://github.com/deepseek-ai/dsh

---

## 效果

在 TUI 对话流里运行 `/billing`,会持久打印一张完整的鲸鱼 ASCII 账单小票(点引导线两端对齐、对终端空格折叠免疫):

<p align="center">
  <img src="https://raw.githubusercontent.com/Ethanz11-creat/dsh-billing-tui/main/docs/receipt.png" alt="dsh-billing-tui /billing 账单小票" width="520" />
</p>

---

## 特性

- **峰谷分时计费**:严格对齐 [DeepSeek 官方计价页](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/),高峰时段收全价、空闲时段打五折,切换时段自动按对应单价结算。
- **`/billing` 命令**:在 TUI 对话流中持久打印鲸鱼 ASCII 账单小票(含每个模型的 `费用小计` 与整体 `费用汇总`),而不是一闪而过的 toast。
- **TUI 状态行**:状态栏实时显示当前会话累计费用 + 高峰/空闲状态。
- **Agent 工具**:暴露 `show_billing`(查费用)与 `check_pricing_period`(查当前峰谷时段)两个工具,Agent 可自行调用。
- **会话继承**:切换模型 fork 出新会话时继承父会话用量,费用不会被清零。
- **去重防堆叠**:连续多次 `/billing` 若没有新的输入/输出,不会重复贴票。
- **只计 DeepSeek 模型**:`deepseek-v4-flash` / `deepseek-v4-pro` 正常计费,其它模型(Claude / GPT / 本地模型等)与未知型号返回 `null`,不计费、不误判。

---

## 示例账单

`/billing` 打印的小票原文如下(与上方截图一致):

```
··························███·······█·······
··························█████··█████······
··········█████████·······████████████······
········███████████████·····█████████·······
······████████████████████··██████··········
······████████████████████████████··········
······███████████████████████████···········
······█████·······██████████████············
·······██·············█████████·············
·········███···········█████████············
············███████████··███████············
············· DEEPSEEK HARNESS ·············
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
========== DeepSeek Harness 账单 ===========
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
编号··············DSH_20260819_152233_9F3A2B
日期······················2026/8/19 15:22:33
价格日期··························2026-08-17
────────────────────────────────────────────
模型·······················deepseek-v4-flash
单价 (每百万, 峰/谷)
缓存命中·························¥0.10/¥0.05
未命中···························¥3.00/¥1.50
输出·····························¥9.00/¥4.50
高峰时段调用 1 次
Input·························128,000 tokens
Cached·························96,000 tokens
Output··························8,600 tokens
Reasoning···························0 tokens
费用小计···························¥0.471000
────────────────────────────────────────────
模型·························deepseek-v4-pro
单价 (每百万, 峰/谷)
缓存命中·························¥0.30/¥0.15
未命中···························¥9.00/¥4.50
输出···························¥27.00/¥13.50
空闲时段调用 1 次
Input··························42,000 tokens
Cached··························4,096 tokens
Output··························3,100 tokens
Reasoning·······················1,024 tokens
费用小计···························¥0.245288
────────────────────────────────────────────
================= 费用汇总 =================
────────────────────────────────────────────
高峰费用···························¥0.471000
空闲费用···························¥0.245288
────────────────────────────────────────────
合计·······························¥0.716288
TOTAL·························282,820 tokens
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
····· SEEK AFTER 18:00. IT COSTS HALF. ·····
········ THANK YOU FOR DIVING DEEP. ········
····|||·||·||||·|·||·|||·||·|·||||·|·|||····
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

---

## 定价

以 [DeepSeek 官方计价页](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/) 为准,单位 **元 / 百万 tokens**,空闲时段价格为高峰时段的一半。

| 模型 | 用量类型 | 高峰 | 空闲 |
| --- | --- | --- | --- |
| `deepseek-v4-flash` | 输入(缓存命中) | ¥0.10 | ¥0.05 |
| | 输入(缓存未命中) | ¥3.00 | ¥1.50 |
| | 输出 | ¥9.00 | ¥4.50 |
| `deepseek-v4-pro` | 输入(缓存命中) | ¥0.30 | ¥0.15 |
| | 输入(缓存未命中) | ¥9.00 | ¥4.50 |
| | 输出 | ¥27.00 | ¥13.50 |

- **高峰时段**:北京时间 `9:00–12:00`、`14:00–18:00`(**每天,含周末**)。
- **空闲时段**:除高峰时段外的其余时间,价格为高峰的 50%。
- **推理 token**:与输出 token 合并后按输出档位计费。
- **缓存命中**:`Cached` 行对应 DeepSeek API 返回的 `prompt_cache_hit_tokens`。

> 时段判断使用固定 `Asia/Shanghai` 时区(`Intl.DateTimeFormat`),不依赖本机时区,避免机器时区非 +08:00 时把峰谷算错。

---

## 安装

前置:本地可运行 dsh(Node.js + pnpm)。插件通过 `dsh.plugin` 的 bundle 机制安装。

```bash
# 方式一:从 npm 安装
dsh plugin --profile demo add dsh-billing-tui

# 方式二:本地目录作为 bundle 安装
dsh plugin --profile demo add ./dsh-billing-tui
```

开发期快速验证可走 `--patch` overlay:

```bash
dsh web --patch ./cordis.yml
```

> `package.json` 中的 `main` 指向预编译产物 `lib/index.js`。仓库已提交 `lib/`,clone 后即可直接使用;如需修改源码后重新构建,见下方「开发」。

---

## 使用

安装后开箱即用,无需额外配置:

| 入口 | 说明 |
| --- | --- |
| `/billing` | 在对话流中持久打印当前会话账单小票(TUI 与 Web 均可用) |
| TUI 状态行 | 实时显示 `费用: ¥X.XXXX [高峰/空闲]` |
| `show_billing` 工具 | Agent 可调用,返回当前会话 token 用量与费用 |
| `check_pricing_period` 工具 | 查询当前处于高峰还是空闲计费时段 |

可选配置(`cordis.patch.yml`):

```yaml
config:
  currency: "CNY"                 # 账单币种:CNY / USD
  pricing_source: "deepseek_official"   # 价格来源,保留字段
```

---

## 工作原理

```
session/event ──► SessionMonitor ──► UsageSnapshot[] ──► pricing ──► 费用
                       │                                        │
                       │  (request/header → 模型名)              │  (峰/谷单价)
                       │  (assistant/chunk usage → 用量)         │
                       ▼                                        ▼
                  继承父会话用量                       generateReceipt ──► /billing 小票
                                                        │
                                                        ├─► tuiStatus 状态行
                                                        └─► tuiRenderers 持久渲染
```

1. 插件订阅 `session/event`,从 `request/header` 读取模型名、从 `assistant/chunk` 的 `type === 'usage'` 读取 token 用量(`inputTokens` / `outputTokens` / `cacheReadTokens` / `reasoningTokens`)。
2. `SessionMonitor` 按会话累积用量快照;切换模型 fork 出的子会话通过 `session.header.parentSession` 继承父会话快照。
3. `peak-detector` 依据北京时间小时数判定峰谷(无周末例外),`pricing` 查表计算各分项费用。
4. `receipt` 生成 ASCII 小票;`/billing` 通过 `tuiRenderers` 把 `dsh-billing/receipt` 事件持久渲染进对话流,并按快照数去重。

---

## 项目结构

```
dsh-billing-tui/
├── src/
│   ├── index.ts            # 插件入口:注册命令/工具/TUI 状态与渲染器、去重与会话继承
│   ├── session-monitor.ts  # 会话用量快照容器,事件驱动累积
│   ├── peak-detector.ts    # 峰谷时段判定(北京时间,无周末例外)
│   ├── pricing.ts          # 官方价格表 + 费用计算
│   ├── receipt.ts          # ASCII 账单小票生成(鲸鱼 logo + 点引导线对齐)
│   └── types.ts            # 核心类型定义
├── test/                   # node:test 单元测试(23 个用例)
├── docs/receipt.png        # README 用的真实终端小票截图
├── scripts/                # 账单样本生成与截图渲染脚本
├── cordis.patch.yml        # 注册 dsh-billing-tui,声明 tuiStatus/tuiRenderers 依赖
├── package.json            # dsh.bundle + peerDependencies + scripts
├── tsconfig.json
└── lib/                    # 预编译产物(已提交,开箱即用)
```

---

## 开发

```bash
# 安装依赖
pnpm install

# 构建(TypeScript → lib/)
pnpm run build

# 类型检查
pnpm run typecheck

# 运行测试
pnpm test
```

---

## FAQ

**`Cached` 一直是 0?**
`Cached` 对应 DeepSeek API 返回的 `prompt_cache_hit_tokens`(缓存命中输入 token)。没有命中上下文缓存时即为 0,属正常现象,并非抓取失败。

**为什么有些模型不计费?**
插件只识别 DeepSeek 官方在售的 `deepseek-v4-flash` 与 `deepseek-v4-pro` 两档;其它模型或未知型号按"未收录 / 不计费"处理,避免把第三方模型价格张冠李戴。

**切换模型后费用被清零?**
不会。切换模型会 fork 出新会话,插件会从 `parentSession` 继承父会话用量快照,账单继续累计。

**连续 `/billing` 会堆叠多张小票吗?**
不会。仅当产生新的 usage 快照(新的输入/输出)时才贴一张新小票;相同的用量重复执行不会重复贴票。

---

## License

[MIT](./LICENSE)

Install

dsh plugin --profile web add github:Ethanz11-creat/dsh-billing-tui

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source