dsh-usage-spend 0.2.0 → 0.2.1
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.md +3 -5
- package/README.zh.md +3 -5
- package/lib/client.js +25 -24
- package/lib/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Shows the session's token usage and an **estimated spend** under the DSH composer, priced at DeepSeek's **peak and off-peak rates**, and appends the amount to the built-in per-turn usage action. Currency and exchange rate are configured on the **Plugins** page.
|
|
4
4
|
|
|
5
|
-
One package is both the bundle (it declares the `usage-cost` row) and the feature itself, so installing it gives you a card on the Plugins page.
|
|
6
|
-
|
|
7
5
|
## What you get
|
|
8
6
|
|
|
9
|
-
- **Composer usage pill**: `85.3M tok · ≈¥3.09 · cache hit 99.4%`, replacing the built-in `usage` row
|
|
7
|
+
- **Composer usage pill**: `85.3M tok · ≈¥3.09 · cache hit 99.4%`, replacing the built-in `usage` row.
|
|
10
8
|
- **Click the card**: the header shows the exact token count and amount, followed by buckets for cache hits, uncached input, cache reads, cache writes, output and the billing window.
|
|
11
9
|
- **Per-turn action**: the built-in `用量 85.3M tok` becomes `85.3M tok · ≈¥3.09`, priced at that turn's end time.
|
|
12
10
|
- **Peak pricing**: Beijing time weekdays 09:00–12:00 and 14:00–18:00 cost double; everything else, weekends and public holidays included, is off-peak.
|
|
13
11
|
- **Plugins page settings**: currency (CNY / USD / both), exchange rate, and whether to show the sidebar balance, with a read-only price table below the form.
|
|
14
|
-
- **Sidebar balance**: `余额 ¥12.34` at the bottom of the sidebar, refreshed every 60 seconds or on click; the grant is in the tooltip; collapsed the sidebar shows a compact amount. Can be turned off.
|
|
12
|
+
- **Sidebar balance**: `余额 ¥12.34` at the bottom of the sidebar, refreshed every 60 seconds or on click; the grant is in the tooltip; collapsed the sidebar shows a compact amount. A `峰` / `谷` badge after the amount names the billing window, and the tooltip spells it out. Can be turned off.
|
|
15
13
|
|
|
16
14
|
## Install
|
|
17
15
|
|
|
@@ -63,7 +61,7 @@ How the numbers are produced:
|
|
|
63
61
|
- Cache writes bill at the cache-miss input price, matching DeepSeek
|
|
64
62
|
- **Per-turn amounts use that turn's end time**, so they are exact
|
|
65
63
|
- **The session total uses the window in effect now**: the whole-log token projection carries no time dimension, so a session cannot be replayed turn by turn. Reopening an old session prices the total at the window you open it in while the per-turn amounts stay put
|
|
66
|
-
- The `峰` / `谷` badge
|
|
64
|
+
- The `峰` / `谷` badge at the end of the sidebar balance line names the window in effect. It is hidden when the sidebar is collapsed or the balance chip is turned off; the card's billing-window row still shows it
|
|
67
65
|
- CNY is the base currency; USD is converted with the configured rate and only affects that column
|
|
68
66
|
- Discounts, granted credit, Search/Fetch fees and the platform's actual bill are **not** included. This is an estimate only.
|
|
69
67
|
|
package/README.zh.md
CHANGED
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
在 DSH 的输入框下方显示本次会话的 token 用量与**估算花费**,按 DeepSeek 官方的**峰谷价**计价,并把金额补到内置的每轮用量按钮上。币种和汇率在 **插件** 页配置。
|
|
4
4
|
|
|
5
|
-
一个包同时是 bundle(声明 `usage-cost` 这一行)和功能本体,装上即出现插件页卡片。
|
|
6
|
-
|
|
7
5
|
## 功能
|
|
8
6
|
|
|
9
|
-
- **底部用量 pill**:`85.3M tok · ≈¥3.09 · 缓存命中 99.4%`,替换内置的 `usage`
|
|
7
|
+
- **底部用量 pill**:`85.3M tok · ≈¥3.09 · 缓存命中 99.4%`,替换内置的 `usage` 行。
|
|
10
8
|
- **点击卡片**:标题行显示精确 token 数与金额,下面是缓存命中、未缓存输入、缓存读取、缓存写入、输出、计费时段。
|
|
11
9
|
- **每轮按钮**:把内置的 `用量 85.3M tok` 改成 `85.3M tok · ≈¥3.09`,金额按该轮结束时间判断峰谷。
|
|
12
10
|
- **峰谷计价**:北京时间工作日 9:00–12:00、14:00–18:00 为高峰(价目 ×2),其余时段含周末与法定节假日为空闲。
|
|
13
11
|
- **插件页配置**:`币种`(人民币 / 美元 / 同时显示)、`汇率(1 USD = ? CNY)`、是否显示左侧栏余额,并在表单下方以只读表格展示当前单价表。
|
|
14
|
-
- **左侧栏余额**:在侧栏底部显示 `余额 ¥12.34`,每 60 秒或点击时刷新;赠金放在 tooltip
|
|
12
|
+
- **左侧栏余额**:在侧栏底部显示 `余额 ¥12.34`,每 60 秒或点击时刷新;赠金放在 tooltip 里;折叠栏显示紧凑金额。金额后面带 `峰` / `谷` 小标签,标明当前的计费时段,悬停 tooltip 里有完整说明。可关闭。
|
|
15
13
|
|
|
16
14
|
## 安装
|
|
17
15
|
|
|
@@ -63,7 +61,7 @@ dsh plugin --profile <profile> add dsh-usage-spend
|
|
|
63
61
|
- 缓存写入按缓存未命中的输入价计费,与官方一致
|
|
64
62
|
- **单轮金额按该轮结束时间**判断峰谷,是精确的
|
|
65
63
|
- **会话总额按当前时段**估算:整份 token 统计没有时间维度,无法回溯每一轮分别落在哪个时段。所以隔天回看老会话时,总额按你打开它时的时段算,而每轮按钮上的金额不变
|
|
66
|
-
-
|
|
64
|
+
- 左侧栏余额那行末尾的 `峰` / `谷` 小标签就是当前用的哪档;侧栏收起、或关掉余额显示时看不到它,卡片里的「计费时段」仍然在
|
|
67
65
|
- 币种默认人民币;选美元时按配置的汇率把人民币换算过去,汇率只影响美元那一栏
|
|
68
66
|
- **不包含**折扣、赠送额度、Search/Fetch 费用或平台实际账单,只用于估算
|
|
69
67
|
|
package/lib/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-usage-
|
|
2
|
+
* dsh-usage-spend — browser half.
|
|
3
3
|
*
|
|
4
4
|
* Contributes:
|
|
5
5
|
* - `conversation.composer.dock` id `usage` at priority -1, replacing the
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* an optional localStorage override. No network request is made for pricing.
|
|
18
18
|
*/
|
|
19
19
|
window.__ModuleLoader__.load({
|
|
20
|
-
id: "dsh-usage-
|
|
20
|
+
id: "dsh-usage-spend",
|
|
21
21
|
factory: (require) => {
|
|
22
22
|
var module = { exports: {} };
|
|
23
23
|
var exports = module.exports;
|
|
@@ -27,8 +27,8 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
const primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
28
28
|
const h = React.createElement;
|
|
29
29
|
|
|
30
|
-
const NS = "dsh-usage-
|
|
31
|
-
const STYLE_ID = "dsh-usage-
|
|
30
|
+
const NS = "dsh-usage-spend";
|
|
31
|
+
const STYLE_ID = "dsh-usage-spend/styles";
|
|
32
32
|
const ENTRY_ID = "usage-cost";
|
|
33
33
|
const CONFIG_KEY = "dsh-usage-spend#usage-cost";
|
|
34
34
|
const CURRENCY_KEY = "dsh.cost.currency";
|
|
@@ -40,8 +40,8 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
const zh = {
|
|
41
41
|
"pill.tokens": "{count} tok",
|
|
42
42
|
"pill.cacheHit": "缓存命中 {percent}%",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"window.peak": "峰",
|
|
44
|
+
"window.offPeak": "谷",
|
|
45
45
|
"dialog.title": "Token 用量",
|
|
46
46
|
"dialog.cacheHit": "缓存命中",
|
|
47
47
|
"dialog.input": "未缓存输入",
|
|
@@ -65,6 +65,8 @@ window.__ModuleLoader__.load({
|
|
|
65
65
|
"config.showBalance": "显示左侧栏余额",
|
|
66
66
|
"config.showBalanceHint": "关闭后不显示余额 chip,也不会请求账号余额。",
|
|
67
67
|
"balance.label": "余额",
|
|
68
|
+
"balance.windowPeak": "当前按高峰价估算(表价 ×2)",
|
|
69
|
+
"balance.windowOffPeak": "当前按空闲价估算",
|
|
68
70
|
"balance.loading": "读取中…",
|
|
69
71
|
"balance.unavailable": "暂不可用",
|
|
70
72
|
"balance.signedOut": "未登录",
|
|
@@ -83,8 +85,8 @@ window.__ModuleLoader__.load({
|
|
|
83
85
|
const en = {
|
|
84
86
|
"pill.tokens": "{count} tok",
|
|
85
87
|
"pill.cacheHit": "cache hit {percent}%",
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
+
"window.peak": "peak",
|
|
89
|
+
"window.offPeak": "off-peak",
|
|
88
90
|
"dialog.title": "Token usage",
|
|
89
91
|
"dialog.cacheHit": "Cache hit",
|
|
90
92
|
"dialog.input": "Uncached input",
|
|
@@ -108,6 +110,8 @@ window.__ModuleLoader__.load({
|
|
|
108
110
|
"config.showBalance": "Show the sidebar balance",
|
|
109
111
|
"config.showBalanceHint": "When off, the balance chip is hidden and no balance request is made.",
|
|
110
112
|
"balance.label": "Balance",
|
|
113
|
+
"balance.windowPeak": "Estimated at peak rates (twice the card)",
|
|
114
|
+
"balance.windowOffPeak": "Estimated at off-peak rates",
|
|
111
115
|
"balance.loading": "Loading…",
|
|
112
116
|
"balance.unavailable": "Unavailable",
|
|
113
117
|
"balance.signedOut": "Not signed in",
|
|
@@ -135,7 +139,8 @@ window.__ModuleLoader__.load({
|
|
|
135
139
|
".dshuc_label{text-overflow:ellipsis;min-width:0;overflow:hidden}",
|
|
136
140
|
".dshuc_sep{color:var(--dsw-alias-separator-primary);margin:0 6px}",
|
|
137
141
|
".dshuc_money{color:var(--dsw-alias-label-secondary)}",
|
|
138
|
-
".dshuc_window{color:var(--dsw-alias-label-tertiary);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xs,4px);padding:0 3px;
|
|
142
|
+
".dshuc_window{flex:none;color:var(--dsw-alias-label-tertiary);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xs,4px);padding:0 3px;font-size:10px;line-height:14px}",
|
|
143
|
+
".dshuc_balance[data-wide=false] .dshuc_window{display:none}",
|
|
139
144
|
".dshuc_panel{z-index:1100;box-sizing:border-box;width:max-content;min-width:min(300px,calc(100vw - 24px),var(--dsh-anchored-max-width,100vw));max-width:min(440px,calc(100vw - 24px),var(--dsh-anchored-max-width,100vw));border-radius:var(--dsw-radius-lg);background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;max-height:var(--dsh-anchored-max-height,none);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;padding:16px;font-size:12px;line-height:18px;position:fixed;overflow:hidden auto}",
|
|
140
145
|
".dshuc_title{color:var(--dsw-alias-label-primary);justify-content:space-between;gap:16px;margin-bottom:8px;font-weight:500;display:flex}",
|
|
141
146
|
".dshuc_titleRule{border-top:.5px solid var(--dsw-alias-border-l2);margin-bottom:10px}",
|
|
@@ -178,7 +183,7 @@ window.__ModuleLoader__.load({
|
|
|
178
183
|
if (typeof document === "undefined") return;
|
|
179
184
|
if (document.querySelector('style[data-plugin-css="' + STYLE_ID + '"]') !== null) return;
|
|
180
185
|
const tag = document.createElement("style");
|
|
181
|
-
tag.dataset.plugin = "dsh-usage-
|
|
186
|
+
tag.dataset.plugin = "dsh-usage-spend";
|
|
182
187
|
tag.dataset.pluginCss = STYLE_ID;
|
|
183
188
|
tag.textContent = CSS;
|
|
184
189
|
document.head.appendChild(tag);
|
|
@@ -342,7 +347,7 @@ window.__ModuleLoader__.load({
|
|
|
342
347
|
if (forms === undefined || typeof forms.get !== "function") return;
|
|
343
348
|
const detach = configStore.attach(forms.get(ENTRY_ID));
|
|
344
349
|
if (typeof scope.effect === "function") {
|
|
345
|
-
scope.effect(() => detach, "dsh-usage-
|
|
350
|
+
scope.effect(() => detach, "dsh-usage-spend: config form");
|
|
346
351
|
}
|
|
347
352
|
});
|
|
348
353
|
} catch {
|
|
@@ -687,6 +692,7 @@ window.__ModuleLoader__.load({
|
|
|
687
692
|
|
|
688
693
|
function BalanceChip({ wide, balance, t }) {
|
|
689
694
|
const config = useConfig();
|
|
695
|
+
const peak = isPeak(Date.now());
|
|
690
696
|
const state = React.useSyncExternalStore(balance.subscribe, balance.getSnapshot, balance.getSnapshot);
|
|
691
697
|
if (!config.showBalance) return null;
|
|
692
698
|
const wallets = state.wallets ?? [];
|
|
@@ -707,11 +713,13 @@ window.__ModuleLoader__.load({
|
|
|
707
713
|
} else {
|
|
708
714
|
value = "…";
|
|
709
715
|
}
|
|
716
|
+
const windowText = t(peak ? "balance.windowPeak" : "balance.windowOffPeak");
|
|
710
717
|
const tooltip =
|
|
711
718
|
state.status === "ready"
|
|
712
719
|
? [
|
|
713
720
|
t("balance.tooltip", { wallets: wallets.length > 0 ? walletListText(wallets) : formatMoney(0, "CNY") }),
|
|
714
721
|
bonusWallets.length > 0 ? t("balance.bonus", { wallets: walletListText(bonusWallets) }) : null,
|
|
722
|
+
windowText,
|
|
715
723
|
t("balance.refresh"),
|
|
716
724
|
]
|
|
717
725
|
.filter((part) => part !== null)
|
|
@@ -740,6 +748,7 @@ window.__ModuleLoader__.load({
|
|
|
740
748
|
h("span", { className: "dshuc_balanceGlyph", "aria-hidden": true }, symbol),
|
|
741
749
|
h("span", { className: "dshuc_balanceLabel" }, t("balance.label")),
|
|
742
750
|
h("span", { className: "dshuc_balanceValue" }, value),
|
|
751
|
+
wide ? h("span", { className: "dshuc_window" }, t(peak ? "window.peak" : "window.offPeak")) : null,
|
|
743
752
|
),
|
|
744
753
|
},
|
|
745
754
|
);
|
|
@@ -787,9 +796,9 @@ window.__ModuleLoader__.load({
|
|
|
787
796
|
};
|
|
788
797
|
const access = scope.remoteAccess;
|
|
789
798
|
if (access !== undefined && typeof access.whenAccess === "function") {
|
|
790
|
-
scope.effect(() => access.whenAccess("account/watch", register), "dsh-usage-
|
|
799
|
+
scope.effect(() => access.whenAccess("account/watch", register), "dsh-usage-spend: balance");
|
|
791
800
|
} else {
|
|
792
|
-
scope.effect(() => register(), "dsh-usage-
|
|
801
|
+
scope.effect(() => register(), "dsh-usage-spend: balance");
|
|
793
802
|
}
|
|
794
803
|
});
|
|
795
804
|
} catch {
|
|
@@ -891,15 +900,7 @@ window.__ModuleLoader__.load({
|
|
|
891
900
|
const cacheHit = cacheHitPercent(usage);
|
|
892
901
|
const money = moneyText(cny, config.currency, config.usdToCny);
|
|
893
902
|
const titleMoney = moneyText(cny, config.currency, config.usdToCny, true);
|
|
894
|
-
const moneyNode =
|
|
895
|
-
money === null
|
|
896
|
-
? null
|
|
897
|
-
: h(
|
|
898
|
-
"span",
|
|
899
|
-
{ className: "dshuc_money" },
|
|
900
|
-
money,
|
|
901
|
-
h("span", { className: "dshuc_window" }, t(peak ? "pill.peak" : "pill.offPeak")),
|
|
902
|
-
);
|
|
903
|
+
const moneyNode = money === null ? null : h("span", { className: "dshuc_money" }, money);
|
|
903
904
|
const cacheHitText = cacheHit === null ? null : t("pill.cacheHit", { percent: cacheHit });
|
|
904
905
|
|
|
905
906
|
const segments = [t("pill.tokens", { count: formatTokens(total) })];
|
|
@@ -1281,7 +1282,7 @@ window.__ModuleLoader__.load({
|
|
|
1281
1282
|
ru: en,
|
|
1282
1283
|
pt: en,
|
|
1283
1284
|
}),
|
|
1284
|
-
"dsh-usage-
|
|
1285
|
+
"dsh-usage-spend: dictionaries",
|
|
1285
1286
|
);
|
|
1286
1287
|
injectStyles();
|
|
1287
1288
|
attachConfig(ctx);
|
|
@@ -1321,7 +1322,7 @@ window.__ModuleLoader__.load({
|
|
|
1321
1322
|
);
|
|
1322
1323
|
}
|
|
1323
1324
|
|
|
1324
|
-
exports.name = "dsh-usage-
|
|
1325
|
+
exports.name = "dsh-usage-spend";
|
|
1325
1326
|
exports.inject = ["slots", "locale"];
|
|
1326
1327
|
exports.apply = apply;
|
|
1327
1328
|
/** Test-only internals (loaded through the stub module factory). */
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Host loader entry for dsh-usage-
|
|
2
|
+
* Host loader entry for dsh-usage-spend.
|
|
3
3
|
*
|
|
4
4
|
* The feature is browser-only: the usage projection, the composer dock and the
|
|
5
5
|
* turn-footer amount all live in the client runtime, and pricing is a local
|
|
@@ -15,6 +15,6 @@ export const Config = z.object({
|
|
|
15
15
|
showBalance: z.boolean().default(true).volatile(),
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
export const name = "dsh-usage-
|
|
18
|
+
export const name = "dsh-usage-spend";
|
|
19
19
|
|
|
20
20
|
export function apply() {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-usage-spend",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Session token usage and estimated spend for DSH, priced with DeepSeek peak and off-peak rates: a composer usage pill, the amount appended to the built-in per-turn usage action, and a settings form for currency and exchange rate.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|