dsh-peak-pricing
oliver0804/dsh-peak-pricing
Show DeepSeek's peak / off-peak pricing period under the DSH Web composer, with a live estimate of what the session has cost.
安装
dsh plugin --profile web add github:oliver0804/dsh-peak-pricingREADME
dsh-peak-pricing
English | 繁體中文
A DeepSeek Harness Web plugin that puts one line under the composer: which DeepSeek pricing period is in force right now, how long it lasts, and what this session has cost so far.
4 轮 · 195 步 │ LLM 17m13s │ 首 token 平均 1.3s │ 缓存命中 100% · TPS 117 tok/s
● 空闲时段 · 1:35:06 后进入高峰 · 本会话 ¥1.69
- Green dot — off-peak. A cheap moment to start a long run.
- Orange dot — peak. Everything costs exactly twice as much.
- The countdown is how long the current rate lasts, to the second.
- The amount is what this session has spent, each increment priced at the rate in force when it arrived.
Hover the row for the full breakdown: model, current rates, the session's four token buckets, and the peak windows.
Install
dsh plugin --profile web add dsh-peak-pricing
Restart dsh web, and the row is there. To confirm the plugin layer mounted:
dsh --profile web --dump-config | grep peak-pricing
Removal is the mirror image:
dsh plugin --profile web remove dsh-peak-pricing
The price table
Effective 2026-08-17 00:00 Beijing time, DeepSeek prices by time of day: peak is 09:00–12:00 and 14:00–18:00 Beijing time, and off-peak — everything else — is exactly half.
| Model | Period | Input (cache hit) | Input (cache miss) | Output |
|---|---|---|---|---|
| deepseek-v4-flash | off-peak | ¥0.05 | ¥1.50 | ¥4.50 |
| peak | ¥0.10 | ¥3.00 | ¥9.00 | |
| deepseek-v4-pro | off-peak | ¥0.15 | ¥4.50 | ¥13.50 |
| peak | ¥0.30 | ¥9.00 | ¥27.00 |
Prices are CNY per million tokens. The table lives in
src/pricing.ts as a plain constant — when DeepSeek
announces new numbers, that is the only thing to edit.
The announcement names no weekend or holiday exception, so the same windows apply every day. Times are computed from UTC with a fixed +8 offset (the PRC observes no daylight saving), so the row is correct in any browser timezone.
How the cost is computed
The harness publishes one tokenUsage projection per session: four cumulative
buckets (cacheReadTokens, uncachedInputTokens, cacheWriteTokens,
outputTokens) with no timestamps. A cumulative total alone cannot say which
tokens were billed at which rate, so this plugin prices increments:
- Each new reading is diffed against the previous one.
- The difference is priced at the rate in force at that moment — which is when those tokens were actually billed.
- The running total is kept in
localStorage, keyed by session id, so a page reload continues the accounting instead of repricing the whole session at whatever rate happens to be current.
A session that runs across 17:55 → 18:05 is therefore billed as ten minutes of peak plus five of off-peak, not fifteen minutes of either.
Two mappings worth stating explicitly:
cacheReadTokensbills as cache-hit input;uncachedInputTokens + cacheWriteTokensbills as cache-miss input. The announcement prices input as hit-or-miss only, and a cache write is the miss that populated the cache.- The first reading of a session has no arrival times to price by, so it is priced whole at the current rate. Everything after it is exact. Opening an old session mid-peak therefore over-estimates its history; the figure converges as the session continues.
If the active model is not in the table (another provider, or a DeepSeek model the announcement does not price), the period and countdown keep working and the amount is suppressed rather than guessed.
This is an estimate for pacing your own work — your DeepSeek invoice is authoritative.
How it is built
One package, both halves, the official plugin shape:
src/pricing.ts— the pure core: table, window rule, bucket pricing. No React, no DOM. The host entry re-exports it, so a host-side consumer can price usage from the same table the row shows.src/client/— the browser half, mounted on theconversation.composer.dockslot (the seat the shipped stats line uses) atorder: 120. It reads the active model throughctx.modelDirectoriessoftly: no hard dependency, and the row degrades to period-only if that service is absent.cordis.patch.yml— the one row that inserts the plugin into a profile.
The browser bundle is built by tsdown into the client module loader's
factory form (window.__ModuleLoader__.load({id, factory})), with react,
react/jsx-runtime and every @deepseek-ai/* package left external — the
runtime serves those, and a second React copy would break hooks.
npm install
npm test # vitest: window boundaries, bucket pricing, accumulation
npm run build # tsc -b (declarations) + tsdown (host ESM + client bundle)
Local install from a tarball, the way this plugin was verified:
npm pack
dsh plugin --profile web add "file:$PWD/dsh-peak-pricing-<version>.tgz"
UI language
The row's copy ships in zh (Simplified Chinese, matching DSH's own UI and
DeepSeek's announcement wording) and en, selected by the harness's language
setting. Both dictionaries are in
src/client/locales.ts — edit and rebuild to change
the wording (e.g. to 尖峰/離峰 in Traditional Chinese).
Plays well with dsh-live-stats
@linxin666/dsh-live-stats flattens the composer dock into one non-wrapping
flex line to merge its TPS readout onto the official stats line. This plugin
injects a small stylesheet that lets that wrapper wrap and claims a full-width
basis for its own row, so the price lands on its own line underneath instead
of squeezing the stats. Without that plugin, the rule is inert.
License
MIT