EasyTZ/dsh-ui-balance ↗★ 0

@easytz/dsh-ui-balance

余额与费用:DeepSeek 余额、日/周/月花费、各模型用量与实时单价。Balance and cost panel for DeepSeek Harness: balance, spend, per-model usage, live pricing. 适合需要监控API实时消费、统计日/周/月模型用量和花费的用户。

패키지
@easytz/dsh-ui-balance
호환성
미검증
Harness peer 범위
^0.1.0-rc.7
Cordis peer 범위
^4.0.1
버전
0.9.0
라이선스
MIT
최근 업데이트
2026. 9. 10.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:EasyTZ/dsh-ui-balance

Usage

  • Sidebar row. Two segments: Balance: xx and Spend: xx/day — the latter is what today has cost so far, and it ticks up live while a reply is streaming. Plus a green "off-peak" / blue "peak" marker for the current pricing window.
  • Click the row to open the detail panel: provider, balance, a per-model usage summary you can switch between day / week / month, a per-model cost summary (same columns as the usage table but filled with money, the fifth column being that row's total, plus a grand-total row) driven by the same period selector, and the current price table for every configured model, normalised to per-million tokens.
  • Where the numbers come from. All three figures are computed by the plugin's host half straight from dsh's own session event log ($DSH_HOME/sessions/**/session.jsonl.zstd). Every assistant message there carries the provider-reported token usage and the model that actually produced it, so the totals cover every call this machine really made — regardless of which workspace the session belongs to, whether you scrolled to it, or whether it happened before this app launch.
  • When they update. The sidebar row is live: the in-flight message is estimated from its character count and folded into today's figure, so it moves while a long reply streams. The panel's tables are the settled view — they refresh about a second after a turn ends, once the event has hit the log, with the provider's exact numbers and no estimate mixed in, so the per-column amounts always add up to the row total. A 20-second poll backs that up, so spend from other windows and background sessions lands too.
  • Official price changes. Prices sync from the official pricing page (once at startup, then every 12 hours). Every time a different table comes back, the plugin appends it to a price timeline along with the moment it first saw it; each message is then priced with the table in effect when that message happened, so a price change never rewrites the spend that came before it. A period that straddles a change says so under the cost table. Since "first seen" is not "took effect", set the plugin's pricingEffectiveFrom (e.g. 2026-09-10T00:00:00+08:00) to align with the official announcement; it calibrates only the most recent change. Peak and off-peak prices are read as two independent tables rather than assuming peak = 2× off-peak, and if DeepSeek ever drops peak pricing the peak/off-peak badge disappears on its own.
  • Model renames and "billed as another model". DeepSeek occasionally makes requests for one model name bill at another model's price — in September 2026 it did so twice: the retired names deepseek-v4-flash and deepseek-v4-flash-vision-exp bill at the Flash rate, and from 2026-09-14 12:00 Beijing time deepseek-v4-pro routes to V4.1 Flash and bills at the Flash rate too. Both go wrong in opposite directions if left unmodelled: the retired names have no row at all in the new table (their usage would show tokens but zero cost), while deepseek-v4-pro still lists the Pro price (billing it that way overcharges by more than 2×). These rules are parsed from the page footnote rather than hard-coded, travel on the timeline with the prices, and are applied per message: a pro call before the cutoff still costs the Pro rate. If DeepSeek later ships V4.1 Pro and drops that footnote, pro goes back to its table price on the next sync while older history keeps the rule that was published at the time. Routed rows are marked ↦ deepseek-flash in the price table with the page's own sentence printed underneath, a rule that has not taken effect yet is announced in advance, and a rule the plugin cannot read is never applied — the sentence is flagged for you to check.
  • Peak hours are parsed from the same page footnote (currently "北京时间周一至周五 9:00 - 12:00、14:00 - 18:00") and travel on the timeline with the prices, so a change to the hours does not re-judge older messages. Judged in Beijing time (a fixed UTC+8 offset, independent of your machine's zone) to the minute, and the panel prints the window in effect. Override with peakDays (e.g. 1-5) and peakWindows (e.g. 9:00-12:00,14:00-18:00, or none for no peak hours) — an override applies to the whole timeline, so it re-prices all history.
  • Statutory holidays follow the official sentence literally, which names only Mon–Fri: National Day or Spring Festival falling on a weekday inside 9–12 / 14–18 is billed at the peak rate, and a make-up workday on a Saturday is off-peak. The plugin does not invent a rule DeepSeek has not published. If DeepSeek ever adds "法定节假日除外" to that footnote, the plugin picks it up on its own — it recognises the phrasing, switches the rule, and fetches that year's holiday calendar (including make-up workdays; the data is a machine-readable mirror of the State Council notice, with the source document linked in papers). No plugin release, no dates to type. That calendar is only fetched when it is actually needed: under the default rule no request is made at all. Override with peakHolidays: auto (default, follow the page) / offpeak / peak; offPeakDates and peakDates remain for what the calendar cannot cover.
  • When it cannot read the rule, it says so. The plugin models weekdays, time windows and holidays — nothing else. If the footnote ever states another billing rule (tiered pricing, a cap, a different time zone), the panel prints that sentence verbatim and flags that it was not understood, rather than pretending the rule is unchanged. Likewise, if the holiday calendar cannot be fetched it says holidays are being counted as peak for now.
  • Sync failures are visible. The price section says when the table was last synced; if the page is unreachable or its structure changed, it says how long it has been failing and why — and keeps using the last real table it has rather than silently swapping in the plugin's built-in defaults.
  • Periods roll over automatically (day at midnight, week on Monday, month on the 1st). Parallel sessions all count toward the same totals, and the usage and cost tables are computed from the same data with the same ordering, so row n is the same model in both.
  • Reset (top right) clears the currently selected period — costs and usage together, with a confirmation step naming the period. Since the figures are recomputed from the log each time, a reset records a "count from here" floor rather than deleting rows; it expires on the next day/week/month boundary. Day/week/month are independent, and the reset is persisted immediately.