@lancecheney/dsh-deepseek-balance 0.1.2 → 0.1.3
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/lib/client.js +30 -5
- package/lib/index.js +111 -62
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -22,13 +22,35 @@ window.__ModuleLoader__.load({
|
|
|
22
22
|
const C = { root: "Dbg1_root", num: "Dbg1_num", sep: "Dbg1_sep", chip: "Dbg1_chip", peak: "Dbg1_peak", offPeak: "Dbg1_offPeak", legacy: "Dbg1_legacy", dimmed: "Dbg1_dimmed", plus: "Dbg1_plus", unit: "Dbg1_unit" };
|
|
23
23
|
const P = { backdrop: "Dp1_backdrop", panel: "Dp1_panel", head: "Dp1_head", avatar: "Dp1_avatar", name: "Dp1_name", key: "Dp1_key", close: "Dp1_close", body: "Dp1_body", stats: "Dp1_stats", statItem: "Dp1_statItem", statValue: "Dp1_statValue", statLabel: "Dp1_statLabel", sepBar: "Dp1_sepBar", balance: "Dp1_balance", balanceBlock: "Dp1_balanceBlock", balanceBlockLabel: "Dp1_balanceBlockLabel", balanceBlockValue: "Dp1_balanceBlockValue", btn: "Dp1_btn", btnPrimary: "Dp1_btnPrimary", section: "Dp1_section", title: "Dp1_title", row: "Dp1_row", twoCol: "Dp1_twoCol", rowTitle: "Dp1_rowTitle", rowTitleGray: "Dp1_rowTitleGray", rowVal: "Dp1_rowVal", rank: "Dp1_rank", monthNav: "Dp1_monthNav", monthGrids: "Dp1_monthGrids", monthGroup: "Dp1_monthGroup", monthGroupTitle: "Dp1_monthGroupTitle", grid: "Dp1_grid", cell: "Dp1_cell", cellFlat: "Dp1_cellFlat", cellPeak: "Dp1_cellPeak", cellOff: "Dp1_cellOff", cellBlue: "Dp1_cellBlue", legend: "Dp1_legend", dot: "Dp1_dot", nameRow: "Dp1_nameRow", edit: "Dp1_edit", editRow: "Dp1_editRow", editInput: "Dp1_editInput" };
|
|
24
24
|
|
|
25
|
-
const MODEL_META = { "deepseek-v4-pro": { label: "DeepSeek-V4-Pro" }, "deepseek-v4-flash": { label: "DeepSeek-
|
|
25
|
+
const MODEL_META = { "deepseek-v4-pro": { label: "DeepSeek-V4-Pro" }, "deepseek-flash": { label: "DeepSeek-Flash" }, "deepseek-v4-flash": { label: "DeepSeek-Flash" }, "deepseek-v4-flash-vision-exp": { label: "DeepSeek-Flash (vision)" } };
|
|
26
26
|
const FALLBACK_PRICING = {
|
|
27
27
|
effectiveFrom: "2026-08-17T00:00:00+08:00",
|
|
28
28
|
weekendFrom: "2026-08-23T00:00:00+08:00",
|
|
29
29
|
currencies: {
|
|
30
|
-
CNY: { symbol: "¥", models: {
|
|
31
|
-
|
|
30
|
+
CNY: { symbol: "¥", models: {
|
|
31
|
+
"deepseek-flash": { eras: [
|
|
32
|
+
{ from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
|
|
33
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 } },
|
|
34
|
+
{ from: null, legacy: { hit: 0.02, miss: 1.0, output: 2.0 } }
|
|
35
|
+
] },
|
|
36
|
+
"deepseek-v4-pro": { eras: [
|
|
37
|
+
{ from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
|
|
38
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.15, miss: 4.5, output: 13.5 }, peak: { hit: 0.30, miss: 9.0, output: 27.0 } },
|
|
39
|
+
{ from: null, legacy: { hit: 0.025, miss: 3.0, output: 6.0 } }
|
|
40
|
+
] }
|
|
41
|
+
} },
|
|
42
|
+
USD: { symbol: "$", models: {
|
|
43
|
+
"deepseek-flash": { eras: [
|
|
44
|
+
{ from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
|
|
45
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 } },
|
|
46
|
+
{ from: null, legacy: { hit: 0.0028, miss: 0.14, output: 0.28 } }
|
|
47
|
+
] },
|
|
48
|
+
"deepseek-v4-pro": { eras: [
|
|
49
|
+
{ from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
|
|
50
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.022, miss: 0.66, output: 1.98 }, peak: { hit: 0.044, miss: 1.32, output: 3.96 } },
|
|
51
|
+
{ from: null, legacy: { hit: 0.003625, miss: 0.435, output: 0.87 } }
|
|
52
|
+
] }
|
|
53
|
+
} }
|
|
32
54
|
}
|
|
33
55
|
};
|
|
34
56
|
const DEFAULT_MODEL = "deepseek-v4-pro";
|
|
@@ -108,8 +130,11 @@ window.__ModuleLoader__.load({
|
|
|
108
130
|
const isPeak = period === "peak";
|
|
109
131
|
const isLegacy = period === "legacy";
|
|
110
132
|
const model = models[modelId] || models[DEFAULT_MODEL] || FALLBACK_PRICING.currencies.CNY.models[DEFAULT_MODEL];
|
|
111
|
-
const
|
|
112
|
-
const
|
|
133
|
+
const eras = Array.isArray(model.eras) ? model.eras : [];
|
|
134
|
+
const nowMs = Date.now();
|
|
135
|
+
const era = eras.find((e) => e.from != null && nowMs >= Date.parse(e.from)) || eras[eras.length - 1] || model;
|
|
136
|
+
const p = (period === "peak" ? era.peak : period === "offPeak" ? era.offPeak : era.legacy) || era.peak || era.offPeak || era.legacy;
|
|
137
|
+
const outputPrice = fmtPrice(p ? p.output : "—");
|
|
113
138
|
const cost = state.usage && state.usage.spend ? state.usage.spend.total : null;
|
|
114
139
|
const plus = reasoningEffort === "max" ? "++" : reasoningEffort === "off" ? "" : "+";
|
|
115
140
|
const periodClass = isLegacy ? C.legacy : isPeak ? C.peak : C.offPeak;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
2
|
-
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
5
4
|
import { homedir } from "node:os";
|
|
@@ -26,7 +25,10 @@ const PRICING_CN_URL = "https://api-docs.deepseek.com/zh-cn/quick_start/pricing/
|
|
|
26
25
|
const PRICING_US_URL = "https://api-docs.deepseek.com/quick_start/pricing/";
|
|
27
26
|
const PRICING_FETCH_TIMEOUT_MS = 15000;
|
|
28
27
|
|
|
29
|
-
/**
|
|
28
|
+
/** Prices per currency. Each model carries an `eras` list (newest first): the
|
|
29
|
+
* currently effective peak/off-peak table plus historical tiers, so tokens are
|
|
30
|
+
* billed at the price in force when they were used. `from: null` is the
|
|
31
|
+
* pre-peak/off-peak legacy (flat) tier. */
|
|
30
32
|
const FALLBACK_PRICING = {
|
|
31
33
|
effectiveFrom: "2026-08-17T00:00:00+08:00",
|
|
32
34
|
weekendFrom: "2026-08-23T00:00:00+08:00",
|
|
@@ -34,46 +36,74 @@ const FALLBACK_PRICING = {
|
|
|
34
36
|
CNY: {
|
|
35
37
|
symbol: "¥",
|
|
36
38
|
models: {
|
|
37
|
-
"deepseek-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
"deepseek-flash": {
|
|
40
|
+
eras: [
|
|
41
|
+
{ from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
|
|
42
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 } },
|
|
43
|
+
{ from: null, legacy: { hit: 0.02, miss: 1.0, output: 2.0 } }
|
|
44
|
+
]
|
|
41
45
|
},
|
|
42
46
|
"deepseek-v4-pro": {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
legacy: { hit: 0.02, miss: 1.0, output: 2.0 },
|
|
49
|
-
peak: { hit: 0.10, miss: 3.0, output: 9.0 },
|
|
50
|
-
offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }
|
|
47
|
+
eras: [
|
|
48
|
+
{ from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
|
|
49
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.15, miss: 4.5, output: 13.5 }, peak: { hit: 0.30, miss: 9.0, output: 27.0 } },
|
|
50
|
+
{ from: null, legacy: { hit: 0.025, miss: 3.0, output: 6.0 } }
|
|
51
|
+
]
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
55
|
USD: {
|
|
55
56
|
symbol: "$",
|
|
56
57
|
models: {
|
|
57
|
-
"deepseek-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
"deepseek-flash": {
|
|
59
|
+
eras: [
|
|
60
|
+
{ from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
|
|
61
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 } },
|
|
62
|
+
{ from: null, legacy: { hit: 0.0028, miss: 0.14, output: 0.28 } }
|
|
63
|
+
]
|
|
61
64
|
},
|
|
62
65
|
"deepseek-v4-pro": {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
legacy: { hit: 0.0028, miss: 0.14, output: 0.28 },
|
|
69
|
-
peak: { hit: 0.014, miss: 0.44, output: 1.32 },
|
|
70
|
-
offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }
|
|
66
|
+
eras: [
|
|
67
|
+
{ from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
|
|
68
|
+
{ from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.022, miss: 0.66, output: 1.98 }, peak: { hit: 0.044, miss: 1.32, output: 3.96 } },
|
|
69
|
+
{ from: null, legacy: { hit: 0.003625, miss: 0.435, output: 0.87 } }
|
|
70
|
+
]
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
+
/** Legacy model names retired/renamed by DeepSeek; their requests are served by
|
|
78
|
+
* DeepSeek-V4.1-Flash and billed at the Flash price. */
|
|
79
|
+
const MODEL_ALIASES = {
|
|
80
|
+
"deepseek-v4-flash": "deepseek-flash",
|
|
81
|
+
"deepseek-v4-flash-vision-exp": "deepseek-flash"
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function resolveModelId(rawModel) {
|
|
85
|
+
const id = typeof rawModel === "string" && rawModel.length > 0 ? rawModel : "";
|
|
86
|
+
return MODEL_ALIASES[id] || id;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Index of the price era in force at `time` (eras are newest-first). */
|
|
90
|
+
function priceEraIndex(modelId, time) {
|
|
91
|
+
const m = FALLBACK_PRICING.currencies.CNY.models[modelId];
|
|
92
|
+
if (!m || !Array.isArray(m.eras)) return 0;
|
|
93
|
+
for (let i = 0; i < m.eras.length; i++) {
|
|
94
|
+
const from = m.eras[i].from;
|
|
95
|
+
if (from === null || from === void 0 || time >= Date.parse(from)) return i;
|
|
96
|
+
}
|
|
97
|
+
return m.eras.length - 1;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Price era for a model at `time`, falling back to legacy/flat when unknown. */
|
|
101
|
+
function priceEraAt(modelId, time) {
|
|
102
|
+
const m = FALLBACK_PRICING.currencies.CNY.models[modelId];
|
|
103
|
+
if (!m || !Array.isArray(m.eras)) return null;
|
|
104
|
+
return m.eras[priceEraIndex(modelId, time)] || null;
|
|
105
|
+
}
|
|
106
|
+
|
|
77
107
|
function json(res, status, body) {
|
|
78
108
|
const payload = JSON.stringify(body);
|
|
79
109
|
res.writeHead(status, {
|
|
@@ -87,7 +117,7 @@ function resolveSettingsSection(ctx) {
|
|
|
87
117
|
try {
|
|
88
118
|
const settings = ctx.get("settings");
|
|
89
119
|
if (settings && typeof settings.get === "function") {
|
|
90
|
-
return settings.get(
|
|
120
|
+
return settings.get("llm-deepseek");
|
|
91
121
|
}
|
|
92
122
|
} catch {}
|
|
93
123
|
return void 0;
|
|
@@ -147,16 +177,16 @@ const number = (match, index) => {
|
|
|
147
177
|
return Number.isFinite(value) ? value : void 0;
|
|
148
178
|
};
|
|
149
179
|
|
|
150
|
-
/** Parse the zh-CN docs page: CNY peak/off-peak table (
|
|
180
|
+
/** Parse the zh-CN docs page: CNY peak/off-peak table (2 columns: flash, pro). */
|
|
151
181
|
function parseCnPricing(html) {
|
|
152
182
|
const text = stripTags(html);
|
|
153
183
|
const grab = (label) => {
|
|
154
|
-
const re = new RegExp(label + "\\s*空闲时段\\s*([\\d.]+)元\\s*([\\d.]+)元\\s
|
|
184
|
+
const re = new RegExp(label + "\\s*空闲时段\\s*([\\d.]+)元\\s*([\\d.]+)元\\s*高峰时段\\s*([\\d.]+)元\\s*([\\d.]+)元");
|
|
155
185
|
const m = text.match(re);
|
|
156
186
|
if (!m) return void 0;
|
|
157
187
|
return {
|
|
158
|
-
offPeak: [number(m, 1), number(m, 2)
|
|
159
|
-
peak: [number(m,
|
|
188
|
+
offPeak: [number(m, 1), number(m, 2)],
|
|
189
|
+
peak: [number(m, 3), number(m, 4)]
|
|
160
190
|
};
|
|
161
191
|
};
|
|
162
192
|
const hit = grab("百万tokens输入\\s*(缓存命中)");
|
|
@@ -171,23 +201,22 @@ function parseCnPricing(html) {
|
|
|
171
201
|
|
|
172
202
|
return {
|
|
173
203
|
models: {
|
|
174
|
-
"deepseek-
|
|
175
|
-
"deepseek-v4-pro": mk(1)
|
|
176
|
-
"deepseek-v4-flash-vision-exp": mk(2)
|
|
204
|
+
"deepseek-flash": mk(0),
|
|
205
|
+
"deepseek-v4-pro": mk(1)
|
|
177
206
|
}
|
|
178
207
|
};
|
|
179
208
|
}
|
|
180
209
|
|
|
181
|
-
/** Parse the English docs page: USD peak/off-peak table (
|
|
210
|
+
/** Parse the English docs page: USD peak/off-peak table (2 columns: flash, pro). */
|
|
182
211
|
function parseUsModels(html) {
|
|
183
212
|
const text = stripTags(html);
|
|
184
213
|
const grab = (label) => {
|
|
185
|
-
const re = new RegExp(label + "\\s+OFF-PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s
|
|
214
|
+
const re = new RegExp(label + "\\s+OFF-PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s+PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)", "i");
|
|
186
215
|
const m = text.match(re);
|
|
187
216
|
if (!m) return void 0;
|
|
188
217
|
return {
|
|
189
|
-
offPeak: [number(m, 1), number(m, 2)
|
|
190
|
-
peak: [number(m,
|
|
218
|
+
offPeak: [number(m, 1), number(m, 2)],
|
|
219
|
+
peak: [number(m, 3), number(m, 4)]
|
|
191
220
|
};
|
|
192
221
|
};
|
|
193
222
|
const hit = grab("1M INPUT TOKENS\\s*\\(CACHE HIT\\)");
|
|
@@ -202,9 +231,8 @@ function parseUsModels(html) {
|
|
|
202
231
|
|
|
203
232
|
return {
|
|
204
233
|
models: {
|
|
205
|
-
"deepseek-
|
|
206
|
-
"deepseek-v4-pro": mk(1)
|
|
207
|
-
"deepseek-v4-flash-vision-exp": mk(2)
|
|
234
|
+
"deepseek-flash": mk(0),
|
|
235
|
+
"deepseek-v4-pro": mk(1)
|
|
208
236
|
}
|
|
209
237
|
};
|
|
210
238
|
}
|
|
@@ -212,15 +240,26 @@ function parseUsModels(html) {
|
|
|
212
240
|
const pricing = { data: FALLBACK_PRICING, fetchedAt: 0, source: "fallback" };
|
|
213
241
|
let pricingRefresh = null;
|
|
214
242
|
|
|
243
|
+
/** Merge freshly parsed current prices into the era in force right now. */
|
|
215
244
|
function mergeLegacy(models, fallbackModels) {
|
|
216
245
|
const result = {};
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
246
|
+
const now = Date.now();
|
|
247
|
+
for (const [id, fb] of Object.entries(fallbackModels)) {
|
|
248
|
+
const parsed = models[id];
|
|
249
|
+
if (!parsed || !Array.isArray(fb.eras)) {
|
|
250
|
+
result[id] = fb;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
let curIdx = fb.eras.length - 1;
|
|
254
|
+
for (let i = 0; i < fb.eras.length; i++) {
|
|
255
|
+
const from = fb.eras[i].from;
|
|
256
|
+
if (from !== null && from !== void 0 && now >= Date.parse(from)) {
|
|
257
|
+
curIdx = i;
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const eras = fb.eras.map((era, i) => (i === curIdx ? { ...era, peak: parsed.peak, offPeak: parsed.offPeak } : era));
|
|
262
|
+
result[id] = { ...fb, eras };
|
|
224
263
|
}
|
|
225
264
|
return result;
|
|
226
265
|
}
|
|
@@ -460,13 +499,16 @@ function aggregateSessions(archivedIds = []) {
|
|
|
460
499
|
else if (r.type === "assistant/chunk" && r.data?.chunk?.type === "usage") usage = r.data.chunk.usage;
|
|
461
500
|
if (usage && time !== null && dedupe.has(r)) {
|
|
462
501
|
const t = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) + (usage.cacheReadTokens ?? 0);
|
|
463
|
-
const
|
|
502
|
+
const modelId = resolveModelId(model);
|
|
503
|
+
const eraIdx = priceEraIndex(modelId, time);
|
|
504
|
+
const era = priceEraAt(modelId, time);
|
|
505
|
+
const period = era && era.legacy ? "flat" : periodOfUsage(time, effectiveFromMs, weekendFromMs);
|
|
464
506
|
const dayKey = beijingDayKey(time);
|
|
465
507
|
tokens += t;
|
|
466
508
|
if (period === "peak") peakTokens += t;
|
|
467
509
|
else if (period === "offPeak") offPeakTokens += t;
|
|
468
510
|
else flatTokens += t;
|
|
469
|
-
const mkModel =
|
|
511
|
+
const mkModel = `${modelId}@${eraIdx}`;
|
|
470
512
|
const b = bucketsFrom(usage);
|
|
471
513
|
dayTokens[dayKey] = dayTokens[dayKey] || {};
|
|
472
514
|
dayTokens[dayKey][mkModel] = dayTokens[dayKey][mkModel] || { flat: zeroBucket(), peak: zeroBucket(), offPeak: zeroBucket() };
|
|
@@ -565,10 +607,9 @@ function computeSpend(summary, currency = "CNY") {
|
|
|
565
607
|
pricing.data.currencies?.CNY ||
|
|
566
608
|
FALLBACK_PRICING.currencies.CNY;
|
|
567
609
|
const models = pricingSet.models || {};
|
|
568
|
-
const defaultModel = models[DEFAULT_MODEL] || { legacy: null, peak: { miss: 0, hit: 0, output: 0 }, offPeak: { miss: 0, hit: 0, output: 0 } };
|
|
569
610
|
const priceOf = (tokens, price) => (tokens || 0) * (price || 0) / 1e6;
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
611
|
+
const eraCost = (b, era) => {
|
|
612
|
+
if (!era) return 0;
|
|
572
613
|
const cost = (bucket, price) => {
|
|
573
614
|
if (!price) return 0;
|
|
574
615
|
return priceOf(bucket.uncachedInputTokens, price.miss)
|
|
@@ -576,22 +617,30 @@ function computeSpend(summary, currency = "CNY") {
|
|
|
576
617
|
+ priceOf(bucket.cacheReadTokens, price.hit)
|
|
577
618
|
+ priceOf(bucket.outputTokens, price.output);
|
|
578
619
|
};
|
|
579
|
-
|
|
620
|
+
if (era.legacy) return cost(b.flat, era.legacy);
|
|
621
|
+
return cost(b.peak, era.peak) + cost(b.offPeak, era.offPeak);
|
|
622
|
+
};
|
|
623
|
+
// Bucket keys are `${modelId}@${eraIndex}` so each token is billed at the
|
|
624
|
+
// price era in force when it was used.
|
|
625
|
+
const bucketCost = (b, key) => {
|
|
626
|
+
const at = typeof key === "string" ? key.lastIndexOf("@") : -1;
|
|
627
|
+
if (at < 0) return 0;
|
|
628
|
+
const modelId = key.slice(0, at);
|
|
629
|
+
const eraIdx = Number(key.slice(at + 1));
|
|
630
|
+
const mm = models[modelId];
|
|
631
|
+
if (!mm || !Array.isArray(mm.eras)) return 0;
|
|
632
|
+
const era = mm.eras[Number.isFinite(eraIdx) ? eraIdx : 0] || mm.eras[mm.eras.length - 1];
|
|
633
|
+
return eraCost(b, era);
|
|
580
634
|
};
|
|
581
635
|
let total = 0;
|
|
582
636
|
for (const [k, b] of Object.entries(summary.byModel || {})) {
|
|
583
|
-
|
|
584
|
-
total += bucketCost(b, models[m] || defaultModel);
|
|
637
|
+
total += bucketCost(b, k);
|
|
585
638
|
}
|
|
586
639
|
const day = (summary.days || {})[beijingDayKey(Date.now())];
|
|
587
640
|
let today = null;
|
|
588
641
|
if (day) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
for (const [m, b] of Object.entries(day.byModel)) today += bucketCost(b, models[m] || defaultModel);
|
|
592
|
-
} else {
|
|
593
|
-
today = bucketCost(day, defaultModel);
|
|
594
|
-
}
|
|
642
|
+
today = 0;
|
|
643
|
+
for (const [k, b] of Object.entries(day.byModel || {})) today += bucketCost(b, k);
|
|
595
644
|
}
|
|
596
645
|
return { total, today, currency };
|
|
597
646
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lancecheney/dsh-deepseek-balance",
|
|
3
3
|
"description": "Session-header DeepSeek API balance, per-conversation spend, and peak/off-peak pricing indicator",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|