@dougen/dsh-deepseek-usage 0.3.1 → 0.4.0
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 +63 -5
- package/lib/client.js +70 -13
- package/lib/index.js +53 -16
- package/lib/pricing.js +3 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
# @dougen/dsh-deepseek-usage
|
|
2
2
|
|
|
3
|
-
DeepSeek
|
|
3
|
+
DeepSeek 余额侧边栏插件(DeepSeek Harness Web UI)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
在 DSH **网页界面**的侧边栏底部常驻显示你的 **DeepSeek 账号余额**(放大显示)与**当前模型档单价**卡片,并提供高峰/空闲计费时段指示灯。
|
|
5
|
+
在 DSH **网页界面**的侧边栏底部常驻显示你的 **DeepSeek 账号余额**(放大显示)与**当前模型档单价**,并提供高峰/空闲计费时段指示灯。界面语言跟随 DSH 语言设置(自动检测浏览器语言,中文界面显示中文,其他语言显示英文)。
|
|
8
6
|
|
|
9
7
|

|
|
10
8
|
|
|
11
9
|
## 功能
|
|
12
10
|
|
|
13
11
|
- **余额**:`¥ 110.00` 大字显示(符号随账号币种自动切换:人民币 `¥` / 美元 `$`)
|
|
14
|
-
- **档单价**:`→|1.5 ⚡0.05 |→4.5`(输入 / 输入缓存 /
|
|
12
|
+
- **档单价**:`→|1.5 ⚡0.05 |→4.5`(输入 / 输入缓存 / 输出,位于卡片右下角;随当前启用模型与峰谷时段自动切换,**切换模型时立即同步**)
|
|
15
13
|
- **峰谷指示灯**:卡片右上角,高峰(9:00–12:00、14:00–18:00 北京时间)橙色,空闲绿色
|
|
16
14
|
- **自动刷新**:每 5 分钟一次;点击卡片任意位置立即刷新
|
|
15
|
+
- **多语言**:界面文案跟随 DSH 语言(中文 / English)
|
|
17
16
|
- 跟随应用明暗主题
|
|
18
17
|
|
|
18
|
+
## 支持范围
|
|
19
|
+
|
|
20
|
+
> ⚠️ 本插件**仅支持 DeepSeek 官方平台**的余额显示:余额来自 DeepSeek 官方 API `GET https://api.deepseek.com/user/balance`(使用 DSH 中已配置的 `DEEPSEEK_API_KEY`)。通过 `DEEPSEEK_BASE_URL` 指向第三方中转/代理时,余额接口可能不可用或返回异常,**不保证兼容**,请使用 DeepSeek 官方平台账号。
|
|
21
|
+
|
|
19
22
|
## 安装
|
|
20
23
|
|
|
21
24
|
需要 DSH CLI,从 npm 安装:
|
|
@@ -50,6 +53,61 @@ dsh plugin --profile web add @dougen/dsh-deepseek-usage
|
|
|
50
53
|
dsh plugin --profile web remove @dougen/dsh-deepseek-usage
|
|
51
54
|
```
|
|
52
55
|
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
# English
|
|
59
|
+
|
|
60
|
+
A sidebar plugin for **DeepSeek Harness Web UI** that shows your **DeepSeek account balance** (large display) and the **current model's unit pricing**, with a peak/off-peak billing indicator. UI language follows the DSH locale (Chinese UI shows Chinese, other languages show English).
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
- **Balance**: `¥ 110.00` large display (symbol follows account currency: `¥` CNY / `$` USD)
|
|
67
|
+
- **Unit pricing**: `→|1.5 ⚡0.05 |→4.5` (input / input cache / output, bottom-right of the card; switches with the active model and peak/off-peak window — **updates instantly when you switch models**)
|
|
68
|
+
- **Peak indicator**: top-right dot, orange during peak hours (9:00–12:00, 14:00–18:00 Beijing Time), green otherwise
|
|
69
|
+
- **Auto refresh**: every 5 minutes; click the card to refresh instantly
|
|
70
|
+
- **i18n**: UI copy follows the DSH locale (Chinese / English)
|
|
71
|
+
- Follows the app light/dark theme
|
|
72
|
+
|
|
73
|
+
## Supported scope
|
|
74
|
+
|
|
75
|
+
> ⚠️ This plugin **only supports DeepSeek's official platform** balance display: balance comes from the official API `GET https://api.deepseek.com/user/balance` (using the `DEEPSEEK_API_KEY` configured in DSH). Pointing `DEEPSEEK_BASE_URL` at a third-party proxy/gateway may break or return unexpected results for the balance endpoint — **not guaranteed to be compatible**. Use an official DeepSeek platform account.
|
|
76
|
+
|
|
77
|
+
## Install
|
|
78
|
+
|
|
79
|
+
Requires the DSH CLI. Install from npm:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
dsh plugin --profile web add @dougen/dsh-deepseek-usage
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Restart the web app (`dsh web`), open http://127.0.0.1:3080 , and the usage card appears at the bottom of the sidebar (below the Cordis panel button).
|
|
86
|
+
|
|
87
|
+
## Data sources
|
|
88
|
+
|
|
89
|
+
| Data | Source |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Balance | Official DeepSeek API `GET /user/balance` (uses `DEEPSEEK_API_KEY` configured in DSH) |
|
|
92
|
+
| Unit pricing / peak window | Built-in price table (DeepSeek official peak/off-peak pricing snapshot, effective 2026-08-17) |
|
|
93
|
+
|
|
94
|
+
Make sure `DEEPSEEK_API_KEY` is configured in DSH (Model settings page) before use.
|
|
95
|
+
|
|
96
|
+
## FAQ
|
|
97
|
+
|
|
98
|
+
**Balance shows "—"?**
|
|
99
|
+
- `DEEPSEEK_API_KEY` is not configured — configure it in DSH settings and restart.
|
|
100
|
+
- Network or API error — the error message is shown below the card.
|
|
101
|
+
|
|
102
|
+
**Price differs from the official one?**
|
|
103
|
+
- The unit price switches with the **active model** and the **peak/off-peak window**; if the active model is not in the built-in price table, `deepseek-chat` pricing is shown with a notice.
|
|
104
|
+
|
|
105
|
+
## Uninstall
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
dsh plugin --profile web remove @dougen/dsh-deepseek-usage
|
|
109
|
+
```
|
|
110
|
+
|
|
53
111
|
## License
|
|
54
112
|
|
|
55
113
|
MIT
|
package/lib/client.js
CHANGED
|
@@ -20,6 +20,23 @@ window.__ModuleLoader__.load({
|
|
|
20
20
|
const POLL_MS = 5 * 60 * 1000;
|
|
21
21
|
const USAGE_PATH = "/api/deepseek-usage";
|
|
22
22
|
|
|
23
|
+
// ---- i18n(DSH locale 服务;zh 为兜底)----
|
|
24
|
+
const NS = "dsh-deepseek-usage";
|
|
25
|
+
const ZH = {
|
|
26
|
+
"price.input": "输入",
|
|
27
|
+
"price.cache": "输入缓存",
|
|
28
|
+
"price.output": "输出",
|
|
29
|
+
"peak.peak": "高峰时段",
|
|
30
|
+
"peak.off": "空闲时段",
|
|
31
|
+
};
|
|
32
|
+
const EN = {
|
|
33
|
+
"price.input": "Input",
|
|
34
|
+
"price.cache": "Input cache",
|
|
35
|
+
"price.output": "Output",
|
|
36
|
+
"peak.peak": "Peak hours",
|
|
37
|
+
"peak.off": "Off-peak hours",
|
|
38
|
+
};
|
|
39
|
+
|
|
23
40
|
// ---- helpers ---------------------------------------------------
|
|
24
41
|
function money(value) {
|
|
25
42
|
const n = Number(value);
|
|
@@ -71,14 +88,34 @@ window.__ModuleLoader__.load({
|
|
|
71
88
|
|
|
72
89
|
// ---- the widget -------------------------------------------------
|
|
73
90
|
function UsageCell(props) {
|
|
91
|
+
const ctx = props.ctx;
|
|
74
92
|
const wide = !!props.wide;
|
|
75
93
|
const [data, setData] = useState(null);
|
|
76
94
|
const [error, setError] = useState("");
|
|
77
95
|
const mounted = useRef(true);
|
|
96
|
+
const locale = ctx && ctx.locale;
|
|
97
|
+
|
|
98
|
+
// 订阅语言变化(DSH locale 服务;不可用时回退中文)。
|
|
99
|
+
const lcSnap = react.useSyncExternalStore(
|
|
100
|
+
(cb) => (locale && typeof locale.subscribe === "function" ? locale.subscribe(cb) : () => {}),
|
|
101
|
+
() => (locale && typeof locale.getSnapshot === "function" ? locale.getSnapshot() : { active: "zh", locales: [], revision: 0 }),
|
|
102
|
+
);
|
|
103
|
+
const lang = lcSnap && lcSnap.active === "en" ? "en" : "zh";
|
|
104
|
+
// locale.bind(ns) 返回绑定命名空间的翻译函数;不可用时回退中文词典。
|
|
105
|
+
const boundT = locale && typeof locale.bind === "function" ? locale.bind(NS) : null;
|
|
106
|
+
const t = (key) => {
|
|
107
|
+
try {
|
|
108
|
+
if (boundT) {
|
|
109
|
+
const v = boundT(key);
|
|
110
|
+
if (typeof v === "string" && v !== key) return v;
|
|
111
|
+
}
|
|
112
|
+
} catch (e) { /* 词典不可用,回退中文 */ }
|
|
113
|
+
return ZH[key] || key;
|
|
114
|
+
};
|
|
78
115
|
|
|
79
116
|
const load = useCallback(async () => {
|
|
80
117
|
try {
|
|
81
|
-
const res = await fetch(USAGE_PATH, { cache: "no-store" });
|
|
118
|
+
const res = await fetch(USAGE_PATH + "?lang=" + lang, { cache: "no-store" });
|
|
82
119
|
let body = null;
|
|
83
120
|
try {
|
|
84
121
|
body = await res.json();
|
|
@@ -93,17 +130,31 @@ window.__ModuleLoader__.load({
|
|
|
93
130
|
if (!mounted.current) return;
|
|
94
131
|
setError(e instanceof Error ? e.message : String(e));
|
|
95
132
|
}
|
|
96
|
-
}, []);
|
|
133
|
+
}, [lang]);
|
|
97
134
|
|
|
98
135
|
useEffect(() => {
|
|
99
136
|
mounted.current = true;
|
|
100
137
|
load();
|
|
101
138
|
const timer = setInterval(load, POLL_MS);
|
|
139
|
+
// 模型切换(写入 settings 触发 document-updated)时立即刷新,价格同步。
|
|
140
|
+
let off = null;
|
|
141
|
+
try {
|
|
142
|
+
if (ctx && ctx.remote && typeof ctx.remote.$on === "function") {
|
|
143
|
+
off = ctx.remote.$on("settings/document-updated", () => {
|
|
144
|
+
try { load(); } catch (e) { /* 忽略刷新错误 */ }
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
} catch (e) {
|
|
148
|
+
off = null;
|
|
149
|
+
}
|
|
102
150
|
return () => {
|
|
103
151
|
mounted.current = false;
|
|
104
152
|
clearInterval(timer);
|
|
153
|
+
try {
|
|
154
|
+
if (typeof off === "function") off();
|
|
155
|
+
} catch (e) { /* 忽略退订错误 */ }
|
|
105
156
|
};
|
|
106
|
-
}, [load]);
|
|
157
|
+
}, [load, ctx]);
|
|
107
158
|
|
|
108
159
|
const balance = data && data.balance ? data.balance : null;
|
|
109
160
|
const tier = data && data.tier ? data.tier : null;
|
|
@@ -117,7 +168,9 @@ window.__ModuleLoader__.load({
|
|
|
117
168
|
background: data && data.peak ? C.peak : C.idle,
|
|
118
169
|
boxShadow: "0 0 4px rgba(0,0,0,.3)",
|
|
119
170
|
};
|
|
120
|
-
const
|
|
171
|
+
const peakTitle = data && data.peak
|
|
172
|
+
? t("peak.peak") + (data.peakHours ? " " + data.peakHours : "")
|
|
173
|
+
: t("peak.off");
|
|
121
174
|
|
|
122
175
|
if (!wide) {
|
|
123
176
|
return h("div", {
|
|
@@ -136,13 +189,12 @@ window.__ModuleLoader__.load({
|
|
|
136
189
|
gap: 5,
|
|
137
190
|
userSelect: "none",
|
|
138
191
|
},
|
|
139
|
-
title,
|
|
140
192
|
onClick: load,
|
|
141
193
|
},
|
|
142
194
|
h("span", { style: { display: "inline-flex", alignItems: "baseline", gap: 3 } },
|
|
143
195
|
h("span", { style: { fontWeight: 700, fontSize: 13, color: C.label } }, symbol),
|
|
144
196
|
h("span", { style: { fontWeight: 700, fontSize: 13, color: C.label } }, money(balance && balance.total))),
|
|
145
|
-
h("span", { style: dot, title:
|
|
197
|
+
h("span", { style: dot, title: peakTitle }));
|
|
146
198
|
}
|
|
147
199
|
|
|
148
200
|
const Price = (icon, label, value) =>
|
|
@@ -170,7 +222,6 @@ window.__ModuleLoader__.load({
|
|
|
170
222
|
fontSize: "12px",
|
|
171
223
|
lineHeight: "15px",
|
|
172
224
|
},
|
|
173
|
-
title,
|
|
174
225
|
onClick: load,
|
|
175
226
|
},
|
|
176
227
|
// 第一行:余额(24px,符号与数字 3px 间距)
|
|
@@ -179,24 +230,30 @@ window.__ModuleLoader__.load({
|
|
|
179
230
|
h("span", { style: { fontWeight: 700, fontSize: 24, color: C.label, lineHeight: "28px" } }, money(balance && balance.total))),
|
|
180
231
|
h("span", {
|
|
181
232
|
style: { position: "absolute", top: 8, right: 9, ...dot },
|
|
182
|
-
title:
|
|
233
|
+
title: peakTitle,
|
|
183
234
|
}),
|
|
184
235
|
// 当前档单价:卡片右下角
|
|
185
236
|
h("span", {
|
|
186
237
|
style: { position: "absolute", right: 9, bottom: 4, display: "inline-flex", alignItems: "center", gap: 5 },
|
|
187
238
|
},
|
|
188
|
-
Price(h(IconIn, null), "
|
|
189
|
-
Price(h(IconCache, null), "
|
|
190
|
-
Price(h(IconOut, null), "
|
|
239
|
+
Price(h(IconIn, null), t("price.input"), tier && tier.input),
|
|
240
|
+
Price(h(IconCache, null), t("price.cache"), tier && tier.cacheRead),
|
|
241
|
+
Price(h(IconOut, null), t("price.output"), tier && tier.output)),
|
|
191
242
|
errs.length
|
|
192
243
|
? h("div", { style: { color: C.err, fontSize: 10, whiteSpace: "pre-wrap" } }, errs.join(" | "))
|
|
193
244
|
: null);
|
|
194
245
|
}
|
|
195
246
|
|
|
196
247
|
// ---- client plugin body -----------------------------------------
|
|
197
|
-
const inject = ["slots"];
|
|
248
|
+
const inject = ["slots", "remote", "locale"];
|
|
198
249
|
|
|
199
250
|
function apply(ctx) {
|
|
251
|
+
// 注册 i18n 词典(DSH locale 服务;不可用时组件回退中文)。
|
|
252
|
+
try {
|
|
253
|
+
if (ctx.locale && typeof ctx.locale.register === "function") {
|
|
254
|
+
ctx.locale.register(NS, { zh: ZH, en: EN });
|
|
255
|
+
}
|
|
256
|
+
} catch (e) { /* 词典注册失败不影响卡片 */ }
|
|
200
257
|
// 注入本包样式:footerActions 换行(卡片独占一行)。
|
|
201
258
|
const tagId = "dsh-deepseek-usage";
|
|
202
259
|
if (typeof document !== "undefined" && document.querySelector(`style[data-plugin-css="${tagId}"]`) === null) {
|
|
@@ -208,7 +265,7 @@ window.__ModuleLoader__.load({
|
|
|
208
265
|
}
|
|
209
266
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
|
|
210
267
|
{ name: "sidebar.footer.action", id: "dsh-usage", order: 100, label: "DeepSeek 用量" },
|
|
211
|
-
(props) => h(UsageCell, { wide: props.wide }),
|
|
268
|
+
(props) => h(UsageCell, { wide: props.wide, ctx }),
|
|
212
269
|
));
|
|
213
270
|
}
|
|
214
271
|
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 注册一个 HTTP 路由:
|
|
5
5
|
*
|
|
6
|
-
* GET /api/deepseek-usage
|
|
6
|
+
* GET /api/deepseek-usage[?lang=zh|en]
|
|
7
7
|
*
|
|
8
8
|
* 返回(JSON):
|
|
9
9
|
* {
|
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
* updatedAt, errors
|
|
15
15
|
* }
|
|
16
16
|
*
|
|
17
|
+
* `lang` 参数(zh 默认)控制错误消息与峰谷文案的语言;UI 其余文案由
|
|
18
|
+
* client 端(DSH locale 服务)本地化。
|
|
19
|
+
*
|
|
17
20
|
* 数据源:余额来自 DeepSeek 官方 GET /user/balance(API Key 经凭证服务解析,
|
|
18
21
|
* 与 llm-deepseek 同一引用,不出本机)。单价与峰谷时段来自内置价格表
|
|
19
|
-
* (lib/pricing.js,DeepSeek
|
|
22
|
+
* (lib/pricing.js,DeepSeek 官方峰谷定价快照)。本插件仅支持 DeepSeek
|
|
23
|
+
* 官方平台余额显示。
|
|
20
24
|
*
|
|
21
25
|
* 安全:路由仅接受本机 Host(127.0.0.1 / localhost / ::1),拦截 DNS
|
|
22
26
|
* rebinding 与 0.0.0.0 绑定下的局域网访问。
|
|
@@ -25,6 +29,7 @@ import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
|
25
29
|
import {
|
|
26
30
|
DEFAULT_MODEL,
|
|
27
31
|
PEAK_HOURS_TEXT,
|
|
32
|
+
PEAK_HOURS_TEXT_EN,
|
|
28
33
|
isPeak,
|
|
29
34
|
unitAt,
|
|
30
35
|
} from "./pricing.js";
|
|
@@ -45,6 +50,22 @@ const JSON_HEADERS = {
|
|
|
45
50
|
"cache-control": "no-store",
|
|
46
51
|
};
|
|
47
52
|
|
|
53
|
+
/** 错误消息字典(zh/en)。 */
|
|
54
|
+
const MESSAGES = {
|
|
55
|
+
zh: {
|
|
56
|
+
noKey: "未配置 DEEPSEEK_API_KEY",
|
|
57
|
+
balanceHttp: (status) => `余额接口 HTTP ${status}`,
|
|
58
|
+
balanceFail: (detail) => `余额获取失败: ${detail}`,
|
|
59
|
+
modelUnknown: (model) => `当前模型 ${model} 不在价格表,档单价按 deepseek-chat 展示`,
|
|
60
|
+
},
|
|
61
|
+
en: {
|
|
62
|
+
noKey: "DEEPSEEK_API_KEY is not configured",
|
|
63
|
+
balanceHttp: (status) => `Balance API HTTP ${status}`,
|
|
64
|
+
balanceFail: (detail) => `Failed to fetch balance: ${detail}`,
|
|
65
|
+
modelUnknown: (model) => `Model ${model} is not in the price table, showing deepseek-chat pricing`,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
48
69
|
function sendJson(res, status, body) {
|
|
49
70
|
res.writeHead(status, JSON_HEADERS);
|
|
50
71
|
res.end(JSON.stringify(body));
|
|
@@ -81,6 +102,17 @@ function isLocalHost(req) {
|
|
|
81
102
|
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
82
103
|
}
|
|
83
104
|
|
|
105
|
+
/** 解析 ?lang= 参数(zh 默认;仅识别 en 为英文,其余中文)。 */
|
|
106
|
+
function resolveLang(req) {
|
|
107
|
+
const url = req.url ?? "";
|
|
108
|
+
const q = url.indexOf("?");
|
|
109
|
+
if (q === -1) return "zh";
|
|
110
|
+
for (const kv of url.slice(q + 1).split("&")) {
|
|
111
|
+
if (kv === "lang=en") return "en";
|
|
112
|
+
}
|
|
113
|
+
return "zh";
|
|
114
|
+
}
|
|
115
|
+
|
|
84
116
|
function apply(ctx) {
|
|
85
117
|
ctx.effect(
|
|
86
118
|
() => ctx.webServer.register({
|
|
@@ -93,6 +125,19 @@ function apply(ctx) {
|
|
|
93
125
|
return sendJson(res, 403, { ok: false, error: "forbidden", message: "仅允许本机访问" });
|
|
94
126
|
}
|
|
95
127
|
|
|
128
|
+
const lang = resolveLang(req);
|
|
129
|
+
const msg = MESSAGES[lang] || MESSAGES.zh;
|
|
130
|
+
|
|
131
|
+
// ---- 当前模型当前档单价(展示用)----
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
let model = DEFAULT_MODEL;
|
|
134
|
+
try {
|
|
135
|
+
const adm = ctx.get("agentDefaultModel");
|
|
136
|
+
const selection = adm && typeof adm.currentSelection === "function" ? adm.currentSelection() : void 0;
|
|
137
|
+
if (selection && typeof selection.model === "string") model = selection.model;
|
|
138
|
+
} catch {}
|
|
139
|
+
const unit = unitAt(model, now);
|
|
140
|
+
|
|
96
141
|
const errors = [];
|
|
97
142
|
|
|
98
143
|
// ---- 余额(官方接口,API Key)----
|
|
@@ -100,7 +145,7 @@ function apply(ctx) {
|
|
|
100
145
|
try {
|
|
101
146
|
const hit = await ctx.credentials.resolve(API_KEY_REF);
|
|
102
147
|
if (hit === void 0) {
|
|
103
|
-
errors.push(
|
|
148
|
+
errors.push(msg.noKey);
|
|
104
149
|
} else {
|
|
105
150
|
const response = await fetch(balanceUrl(), {
|
|
106
151
|
headers: { Authorization: `Bearer ${hit.value}`, Accept: "application/json" },
|
|
@@ -108,7 +153,7 @@ function apply(ctx) {
|
|
|
108
153
|
});
|
|
109
154
|
const text = await response.text();
|
|
110
155
|
if (!response.ok) {
|
|
111
|
-
errors.push(
|
|
156
|
+
errors.push(msg.balanceHttp(response.status));
|
|
112
157
|
} else {
|
|
113
158
|
const body = JSON.parse(text);
|
|
114
159
|
const infos = body && Array.isArray(body.balance_infos) ? body.balance_infos : [];
|
|
@@ -121,25 +166,17 @@ function apply(ctx) {
|
|
|
121
166
|
}
|
|
122
167
|
}
|
|
123
168
|
} catch (error) {
|
|
124
|
-
errors.push(
|
|
169
|
+
errors.push(msg.balanceFail(error instanceof Error ? error.message : String(error)));
|
|
125
170
|
}
|
|
126
171
|
|
|
127
|
-
// ----
|
|
128
|
-
|
|
129
|
-
let model = DEFAULT_MODEL;
|
|
130
|
-
try {
|
|
131
|
-
const adm = ctx.get("agentDefaultModel");
|
|
132
|
-
const selection = adm && typeof adm.currentSelection === "function" ? adm.currentSelection() : void 0;
|
|
133
|
-
if (selection && typeof selection.model === "string") model = selection.model;
|
|
134
|
-
} catch {}
|
|
135
|
-
const unit = unitAt(model, now);
|
|
136
|
-
if (!unit.known) errors.push(`当前模型 ${model} 不在价格表,档单价按 deepseek-chat 展示`);
|
|
172
|
+
// ---- 档单价提示(未知模型回退 chat 档)----
|
|
173
|
+
if (!unit.known) errors.push(msg.modelUnknown(model));
|
|
137
174
|
|
|
138
175
|
sendJson(res, 200, {
|
|
139
176
|
ok: true,
|
|
140
177
|
balance,
|
|
141
178
|
peak: isPeak(now),
|
|
142
|
-
peakHours: PEAK_HOURS_TEXT,
|
|
179
|
+
peakHours: lang === "en" ? PEAK_HOURS_TEXT_EN : PEAK_HOURS_TEXT,
|
|
143
180
|
tier: {
|
|
144
181
|
input: unit.input,
|
|
145
182
|
cacheRead: unit.cacheRead,
|
package/lib/pricing.js
CHANGED
|
@@ -29,8 +29,10 @@ export const DEFAULT_MODEL = 'deepseek-v4-flash';
|
|
|
29
29
|
|
|
30
30
|
/** 高峰时段窗口(北京时间,含起点不含终点)。 */
|
|
31
31
|
export const PEAK_WINDOWS = [[9, 12], [14, 18]];
|
|
32
|
-
/**
|
|
32
|
+
/** 高峰时段展示文案(中文)。 */
|
|
33
33
|
export const PEAK_HOURS_TEXT = '9:00–12:00、14:00–18:00(北京时间)';
|
|
34
|
+
/** 高峰时段展示文案(英文)。 */
|
|
35
|
+
export const PEAK_HOURS_TEXT_EN = '9:00–12:00, 14:00–18:00 (Beijing Time)';
|
|
34
36
|
|
|
35
37
|
/** 某时刻的北京时间小时(0–23)。 */
|
|
36
38
|
export function shanghaiHour(ms) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dougen/dsh-deepseek-usage",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DeepSeek
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "DeepSeek 余额侧边栏插件:余额(官方 API)、当前档单价与峰谷时段指示灯,支持中/英文界面。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"files": [
|