diff --git a/README.md b/README.md index bc3a3a6..c7fef32 100644 --- a/README.md +++ b/README.md @@ -148,16 +148,16 @@ Costs are resolved with priority **user override file > builtin list price > fal ```json { - "deepseek-v4-flash": { + "deepseek-flash": { "offPeak": { - "cny": { "cacheMissInput": 1.5, "cacheHitInput": 0.05, "output": 4.5 }, - "usd": { "cacheMissInput": 0.22, "cacheHitInput": 0.007, "output": 0.66 } + "cny": { "cacheMissInput": 1, "cacheHitInput": 0.02, "output": 4 }, + "usd": { "cacheMissInput": 0.15, "cacheHitInput": 0.003, "output": 0.6 } }, "peak": { - "cny": { "cacheMissInput": 3.0, "cacheHitInput": 0.10, "output": 9.0 }, - "usd": { "cacheMissInput": 0.44, "cacheHitInput": 0.014, "output": 1.32 } + "cny": { "cacheMissInput": 2, "cacheHitInput": 0.04, "output": 8 }, + "usd": { "cacheMissInput": 0.3, "cacheHitInput": 0.006, "output": 1.2 } }, - "verifiedAt": 1755100800000 + "verifiedAt": 1788998400000 } } ``` diff --git a/README_ZH.md b/README_ZH.md index ab05fae..5968d4f 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -168,16 +168,16 @@ dsh web --profile web ```json { - "deepseek-v4-flash": { + "deepseek-flash": { "offPeak": { - "cny": { "cacheMissInput": 1.5, "cacheHitInput": 0.05, "output": 4.5 }, - "usd": { "cacheMissInput": 0.22, "cacheHitInput": 0.007, "output": 0.66 } + "cny": { "cacheMissInput": 1, "cacheHitInput": 0.02, "output": 4 }, + "usd": { "cacheMissInput": 0.15, "cacheHitInput": 0.003, "output": 0.6 } }, "peak": { - "cny": { "cacheMissInput": 3.0, "cacheHitInput": 0.10, "output": 9.0 }, - "usd": { "cacheMissInput": 0.44, "cacheHitInput": 0.014, "output": 1.32 } + "cny": { "cacheMissInput": 2, "cacheHitInput": 0.04, "output": 8 }, + "usd": { "cacheMissInput": 0.3, "cacheHitInput": 0.006, "output": 1.2 } }, - "verifiedAt": 1755100800000 + "verifiedAt": 1788998400000 } } ``` diff --git a/src/pricing/source.ts b/src/pricing/source.ts index 8794d9b..70af990 100644 --- a/src/pricing/source.ts +++ b/src/pricing/source.ts @@ -31,23 +31,25 @@ export interface PricingSource { /** * 当前官方在售模型定价表(双币种 / 1M tokens,区分高峰/空闲时段)。 - * 来源:官方定价页(2026-08-26 核验) + * 来源:官方定价页(2026-09-10 核验) * - 中文页 https://api-docs.deepseek.com/zh-cn/quick_start/pricing(CNY 报价) * - 英文页 https://api-docs.deepseek.com/quick_start/pricing(USD 报价) * 高峰时段(北京时间周一至周五 09:00–12:00、14:00–18:00 = UTC 01:00–04:00、06:00–10:00) * 价格为空闲时段的两倍。 */ -export const BUILTIN_PRICING: Record = { - 'deepseek-v4-flash': { - offPeak: { - cny: { cacheMissInput: 1.5, cacheHitInput: 0.05, output: 4.5 }, - usd: { cacheMissInput: 0.22, cacheHitInput: 0.007, output: 0.66 }, - }, - peak: { - cny: { cacheMissInput: 3.0, cacheHitInput: 0.10, output: 9.0 }, - usd: { cacheMissInput: 0.44, cacheHitInput: 0.014, output: 1.32 }, - }, +const FLASH_PRICING: ModelPricing = { + offPeak: { + cny: { cacheMissInput: 1, cacheHitInput: 0.02, output: 4 }, + usd: { cacheMissInput: 0.15, cacheHitInput: 0.003, output: 0.6 }, }, + peak: { + cny: { cacheMissInput: 2, cacheHitInput: 0.04, output: 8 }, + usd: { cacheMissInput: 0.3, cacheHitInput: 0.006, output: 1.2 }, + }, +} + +export const BUILTIN_PRICING: Record = { + 'deepseek-flash': FLASH_PRICING, 'deepseek-v4-pro': { offPeak: { cny: { cacheMissInput: 4.5, cacheHitInput: 0.15, output: 13.5 }, @@ -58,23 +60,21 @@ export const BUILTIN_PRICING: Record = { usd: { cacheMissInput: 1.32, cacheHitInput: 0.044, output: 3.96 }, }, }, - 'deepseek-v4-flash-vision-exp': { - offPeak: { - cny: { cacheMissInput: 1.5, cacheHitInput: 0.05, output: 4.5 }, - usd: { cacheMissInput: 0.22, cacheHitInput: 0.007, output: 0.66 }, - }, - peak: { - cny: { cacheMissInput: 3.0, cacheHitInput: 0.10, output: 9.0 }, - usd: { cacheMissInput: 0.44, cacheHitInput: 0.014, output: 1.32 }, - }, - }, } -/** 内置表的核验日期(来源:官方定价页中/英文版,2026-08-26 抓取核验)。 */ -export const BUILTIN_VERIFIED_AT = Date.parse('2026-08-26T00:00:00Z') +/** + * 旧模型名兼容: + * - `deepseek-v4-flash` / `deepseek-v4-flash-vision-exp` 已并入 `deepseek-flash`, + * 仍按同一价格表解析,避免历史会话突然变成「未定价模型」。 + */ +BUILTIN_PRICING['deepseek-v4-flash'] = FLASH_PRICING +BUILTIN_PRICING['deepseek-v4-flash-vision-exp'] = FLASH_PRICING + +/** 内置表的核验日期(来源:官方定价页中/英文版,2026-09-10 抓取核验)。 */ +export const BUILTIN_VERIFIED_AT = Date.parse('2026-09-10T00:00:00Z') -/** 未收录模型回退:按 deepseek-v4-flash 刊例价估算并标记 ≈。 */ -export const FALLBACK_PRICING: ModelPricing = BUILTIN_PRICING['deepseek-v4-flash'] +/** 未收录模型回退:按 deepseek-flash 刊例价估算并标记 ≈。 */ +export const FALLBACK_PRICING: ModelPricing = FLASH_PRICING /** 前缀匹配(如带日期后缀的模型版本);精确匹配优先。 */ function matchEntry(table: Record, model: string): T | null { diff --git a/tests/core.test.mjs b/tests/core.test.mjs index 2e69469..00ca057 100644 --- a/tests/core.test.mjs +++ b/tests/core.test.mjs @@ -72,17 +72,18 @@ test('foldTurnUsage ignores malformed or negative usage samples', () => { }) test('pricing matches the documented DeepSeek V4 prices (CNY + USD, peak/off-peak)', () => { - assert.deepEqual(PRICING['deepseek-v4-flash'], { + assert.deepEqual(PRICING['deepseek-flash'], { offPeak: { - cny: { cacheMissInput: 1.5, cacheHitInput: 0.05, output: 4.5 }, - usd: { cacheMissInput: 0.22, cacheHitInput: 0.007, output: 0.66 }, + cny: { cacheMissInput: 1, cacheHitInput: 0.02, output: 4 }, + usd: { cacheMissInput: 0.15, cacheHitInput: 0.003, output: 0.6 }, }, peak: { - cny: { cacheMissInput: 3.0, cacheHitInput: 0.10, output: 9.0 }, - usd: { cacheMissInput: 0.44, cacheHitInput: 0.014, output: 1.32 }, + cny: { cacheMissInput: 2, cacheHitInput: 0.04, output: 8 }, + usd: { cacheMissInput: 0.3, cacheHitInput: 0.006, output: 1.2 }, }, }) - assert.deepEqual(PRICING['deepseek-v4-flash-vision-exp'], PRICING['deepseek-v4-flash']) + assert.deepEqual(PRICING['deepseek-v4-flash'], PRICING['deepseek-flash']) + assert.deepEqual(PRICING['deepseek-v4-flash-vision-exp'], PRICING['deepseek-flash']) assert.equal(cacheHitPercent({ uncachedInputTokens: 50, outputTokens: 0, cacheReadTokens: 50, cacheWriteTokens: 0 }), 50) // 时刻未知 → 高峰价保守估算:1M 未命中输入 + 1M 输出(v4-pro 高峰 CNY = 9 + 27) assert.equal(estimateCost({ uncachedInputTokens: 1_000_000, outputTokens: 1_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 }, 'deepseek-v4-pro').cny, 36) diff --git a/tests/pricing.test.mjs b/tests/pricing.test.mjs index ca02855..5772038 100644 --- a/tests/pricing.test.mjs +++ b/tests/pricing.test.mjs @@ -19,14 +19,14 @@ import { tierAt, } from '../lib/index.js' -/** 2026-08-26 内置刊例价(双币种 /1M,高峰/空闲)。 */ +/** 2026-09-10 内置刊例价(双币种 /1M,高峰/空闲)。 */ const FLASH_OFF_PEAK = { - cny: { cacheMissInput: 1.5, cacheHitInput: 0.05, output: 4.5 }, - usd: { cacheMissInput: 0.22, cacheHitInput: 0.007, output: 0.66 }, + cny: { cacheMissInput: 1, cacheHitInput: 0.02, output: 4 }, + usd: { cacheMissInput: 0.15, cacheHitInput: 0.003, output: 0.6 }, } const FLASH_PEAK = { - cny: { cacheMissInput: 3.0, cacheHitInput: 0.10, output: 9.0 }, - usd: { cacheMissInput: 0.44, cacheHitInput: 0.014, output: 1.32 }, + cny: { cacheMissInput: 2, cacheHitInput: 0.04, output: 8 }, + usd: { cacheMissInput: 0.3, cacheHitInput: 0.006, output: 1.2 }, } const PRO_OFF_PEAK = { cny: { cacheMissInput: 4.5, cacheHitInput: 0.15, output: 13.5 }, @@ -42,9 +42,10 @@ test('builtin source resolves exact and prefixed models, misses unknown', () => assert.deepEqual(source.resolve('deepseek-v4-pro').pricing.offPeak, PRO_OFF_PEAK) assert.deepEqual(source.resolve('deepseek-v4-pro').pricing.peak, PRO_PEAK) // 前缀匹配(带日期后缀的模型版本) - assert.equal(source.resolve('deepseek-v4-flash-2026-08-01').pricing.offPeak.cny.output, 4.5) - assert.equal(source.resolve('deepseek-v4-flash-2026-08-01').pricing.offPeak.usd.output, 0.66) - assert.equal(source.resolve('deepseek-v4-flash-2026-08-01').pricing.peak.usd.output, 1.32) + assert.equal(source.resolve('deepseek-flash-2026-09-01').pricing.offPeak.cny.output, 4) + assert.equal(source.resolve('deepseek-flash-2026-09-01').pricing.offPeak.usd.output, 0.6) + assert.equal(source.resolve('deepseek-flash-2026-09-01').pricing.peak.usd.output, 1.2) + assert.deepEqual(source.resolve('deepseek-flash').pricing, { offPeak: FLASH_OFF_PEAK, peak: FLASH_PEAK }) assert.deepEqual(source.resolve('deepseek-v4-flash-vision-exp').pricing.offPeak, FLASH_OFF_PEAK) assert.deepEqual(source.resolve('deepseek-v4-flash-vision-exp').pricing.peak, FLASH_PEAK) assert.equal(source.resolve('unknown-model').pricing, null) @@ -106,12 +107,12 @@ test('costSplitAt bills in both official currencies per tier', () => { const usage = { uncachedInputTokens: 1_000_000, outputTokens: 1_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 } const offPeakAt = Date.UTC(1970, 0, 1, 0, 0, 0) // 北京时间 08:00 const peakAt = Date.UTC(1970, 0, 1, 2, 0, 0) // 北京时间 10:00 - // 空闲:flash 未命中 1.5 + 输出 4.5(CNY);0.22 + 0.66(USD) - assert.deepEqual(costSplitAt(usage, PRICING['deepseek-v4-flash'], offPeakAt, 'cny'), { input: 1.5, cacheRead: 0, output: 4.5, total: 6 }) - assert.deepEqual(costSplitAt(usage, PRICING['deepseek-v4-flash'], offPeakAt, 'usd'), { input: 0.22, cacheRead: 0, output: 0.66, total: 0.88 }) + // 空闲:flash 未命中 1 + 输出 4(CNY);0.15 + 0.6(USD) + assert.deepEqual(costSplitAt(usage, PRICING['deepseek-flash'], offPeakAt, 'cny'), { input: 1, cacheRead: 0, output: 4, total: 5 }) + assert.deepEqual(costSplitAt(usage, PRICING['deepseek-flash'], offPeakAt, 'usd'), { input: 0.15, cacheRead: 0, output: 0.6, total: 0.75 }) // 高峰 = 空闲 × 2 - assert.deepEqual(costSplitAt(usage, PRICING['deepseek-v4-flash'], peakAt, 'cny'), { input: 3, cacheRead: 0, output: 9, total: 12 }) - assert.deepEqual(costSplitAt(usage, PRICING['deepseek-v4-flash'], peakAt, 'usd'), { input: 0.44, cacheRead: 0, output: 1.32, total: 1.76 }) + assert.deepEqual(costSplitAt(usage, PRICING['deepseek-flash'], peakAt, 'cny'), { input: 2, cacheRead: 0, output: 8, total: 10 }) + assert.deepEqual(costSplitAt(usage, PRICING['deepseek-flash'], peakAt, 'usd'), { input: 0.3, cacheRead: 0, output: 1.2, total: 1.5 }) }) test('parsePricingFile validates entries and accepts dual-currency + legacy shapes', () => { @@ -239,12 +240,14 @@ test('file source serves prefix matches and refresh after rewrite', async () => }) test('estimateCost / pricingFor keep v0.1 compat semantics', () => { - assert.deepEqual(PRICING['deepseek-v4-flash'], { peak: FLASH_PEAK, offPeak: FLASH_OFF_PEAK }) + assert.deepEqual(PRICING['deepseek-flash'], { peak: FLASH_PEAK, offPeak: FLASH_OFF_PEAK }) + assert.deepEqual(PRICING['deepseek-v4-flash'], PRICING['deepseek-flash']) // 时刻未知 → 按高峰价保守估算:1M 未命中输入 + 1M 输出(v4-pro 高峰 CNY = 9 + 27) assert.equal(estimateCost({ uncachedInputTokens: 1_000_000, outputTokens: 1_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 }, 'deepseek-v4-pro').cny, 36) + assert.equal(pricingFor('deepseek-flash').estimated, false) assert.equal(pricingFor('deepseek-v4-flash').estimated, false) assert.equal(pricingFor('unknown-model').estimated, true) - assert.equal(BUILTIN_VERIFIED_AT, Date.parse('2026-08-26T00:00:00Z')) + assert.equal(BUILTIN_VERIFIED_AT, Date.parse('2026-09-10T00:00:00Z')) }) function responseRecorder() { @@ -274,9 +277,9 @@ test('/pricing route exposes builtin + fallback + models snapshot', async () => const body = JSON.parse(recorder.body) assert.equal(body.ok, true) assert.equal(body.builtinVerifiedAt, BUILTIN_VERIFIED_AT) - assert.equal(body.fallback.pricing.offPeak.cny.output, 4.5) - assert.equal(body.fallback.pricing.offPeak.usd.output, 0.66) - assert.equal(body.fallback.pricing.peak.usd.output, 1.32) + assert.equal(body.fallback.pricing.offPeak.cny.output, 4) + assert.equal(body.fallback.pricing.offPeak.usd.output, 0.6) + assert.equal(body.fallback.pricing.peak.usd.output, 1.2) const models = body.models.map((m) => m.model) assert.ok(models.includes('deepseek-v4-flash')) assert.ok(models.includes('deepseek-v4-pro')) diff --git a/tests/rounds.test.mjs b/tests/rounds.test.mjs index 1aa05a9..3b57d17 100644 --- a/tests/rounds.test.mjs +++ b/tests/rounds.test.mjs @@ -3,14 +3,14 @@ import test from 'node:test' import { apply, foldRounds, foldTurnUsage, tierAt } from '../lib/index.js' -/** 2026-08-17 内置刊例价(双币种 /1M):flash 高峰/空闲。 */ +/** 2026-09-10 内置刊例价(双币种 /1M):flash 高峰/空闲。 */ const FLASH_PEAK = { - cny: { cacheMissInput: 3.0, cacheHitInput: 0.10, output: 9.0 }, - usd: { cacheMissInput: 0.44, cacheHitInput: 0.014, output: 1.32 }, + cny: { cacheMissInput: 2, cacheHitInput: 0.04, output: 8 }, + usd: { cacheMissInput: 0.3, cacheHitInput: 0.006, output: 1.2 }, } const FLASH_OFF_PEAK = { - cny: { cacheMissInput: 1.5, cacheHitInput: 0.05, output: 4.5 }, - usd: { cacheMissInput: 0.22, cacheHitInput: 0.007, output: 0.66 }, + cny: { cacheMissInput: 1, cacheHitInput: 0.02, output: 4 }, + usd: { cacheMissInput: 0.15, cacheHitInput: 0.003, output: 0.6 }, } /** 合成事件流工具:seq 自动递增,time 由调用方给定。 */ @@ -68,12 +68,12 @@ test('foldRounds computes per-round timing, TTFT, TPS, model attribution and cos assert.equal(r1.cost.estimated, false) // 轮 1 开始于 1970-01-01T00:00:01Z = 北京时间 08:00(空闲时段)→ 空闲价 assert.equal(tierAt(r1.startedAt), 'offPeak') - assert.equal(r1.cost.cny.input, (100 / 1_000_000) * 1.5) - assert.equal(r1.cost.cny.cacheRead, (30 / 1_000_000) * 0.05) - assert.equal(r1.cost.cny.output, (20 / 1_000_000) * 4.5) - assert.equal(r1.cost.usd.input, (100 / 1_000_000) * 0.22) - assert.equal(r1.cost.usd.cacheRead, (30 / 1_000_000) * 0.007) - assert.equal(r1.cost.usd.output, (20 / 1_000_000) * 0.66) + assert.equal(r1.cost.cny.input, (100 / 1_000_000) * 1) + assert.equal(r1.cost.cny.cacheRead, (30 / 1_000_000) * 0.02) + assert.equal(r1.cost.cny.output, (20 / 1_000_000) * 4) + assert.equal(r1.cost.usd.input, (100 / 1_000_000) * 0.15) + assert.equal(r1.cost.usd.cacheRead, (30 / 1_000_000) * 0.003) + assert.equal(r1.cost.usd.output, (20 / 1_000_000) * 0.6) const r2 = rounds.find((r) => r.turn === 2) assert.ok(r2, 'round 2 present') @@ -101,11 +101,11 @@ test('foldRounds bills peak vs off-peak rounds by their start time', () => { const offPeak = rounds.find((r) => r.turn === 2) assert.equal(tierAt(peak.startedAt), 'peak') assert.equal(tierAt(offPeak.startedAt), 'offPeak') - // 1M 未命中输入:高峰 = 空闲 × 2(CNY 3.0/1.5;USD 0.44/0.22) - assert.equal(peak.cost.cny.total, 3.0) - assert.equal(peak.cost.usd.total, 0.44) - assert.equal(offPeak.cost.cny.total, 1.5) - assert.equal(offPeak.cost.usd.total, 0.22) + // 1M 未命中输入:高峰 = 空闲 × 2(CNY 2/1;USD 0.3/0.15) + assert.equal(peak.cost.cny.total, 2) + assert.equal(peak.cost.usd.total, 0.3) + assert.equal(offPeak.cost.cny.total, 1) + assert.equal(offPeak.cost.usd.total, 0.15) }) test('foldRounds tolerates missing turn/end (open round) and missing model', () => { @@ -150,9 +150,9 @@ test('foldRounds marks unknown models and uses fallback pricing', () => { assert.equal(rounds[0].cost.unknownModel, true) assert.equal(rounds[0].cost.estimated, true) assert.equal(rounds[0].cost.source, 'fallback') - // 轮开始于北京时间 08:00(空闲)→ 1M token × flash 空闲未命中价(CNY 1.5 / USD 0.22) - assert.equal(rounds[0].cost.cny.total, 1.5) - assert.equal(rounds[0].cost.usd.total, 0.22) + // 轮开始于北京时间 08:00(空闲)→ 1M token × flash 空闲未命中价(CNY 1 / USD 0.15) + assert.equal(rounds[0].cost.cny.total, 1) + assert.equal(rounds[0].cost.usd.total, 0.15) }) test('foldTurnUsage stays compatible with the v0.1 semantics', () => {