From 9e6577f610eac441204fed81f80eb477ac8f35a5 Mon Sep 17 00:00:00 2001 From: argszero Date: Mon, 14 Sep 2026 18:58:17 +0800 Subject: [PATCH] fix(catalog): rename the DeepSeek flash model to its canonical id deepseek-flash The DeepSeek docs (https://api-docs.deepseek.com/zh-cn/, checked 2026-09-14) now name the model `deepseek-flash`; the old `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp` are retired (requests to those names still answer, but DeepSeek routes them to DeepSeek-V4.1-Flash and bills Flash prices). `deepseek-v4-pro` is unchanged. Why this mattered: `POST /api/sharings` validates that a share is priceable with `SELECT 1 FROM models WHERE provider = ?1 AND model = ?2`, so listing a share of the new model was rejected because the name was in neither `config/config.example.toml` nor the seeded `models` table. Rename only - deliberately no alias handling. The retired names are dead and upstream-routed, and "a deleted model bills 0" is the documented behaviour (`admin.models.sub`), so dropping them introduces no new defect class. - config/config.example.toml: the flash row becomes `deepseek-flash` with the official prices (idle cache-hit 0.02 / uncached 1.0 / output 4.0 CNY per 1M; peak 0.04 / 2.0 / 8.0), `vision = true` (V4.1-Flash is natively multimodal) and context 1M / max output 384K; the separate `deepseek-v4-flash-vision-exp` entry is folded into it, so the catalogue is 13 models. - ui/js/data.js: the MODELS / MARKET mirrors follow (13 models, 7 on sale). - src/catalog_gate.rs: MODEL_COUNT 14 -> 13, KNOWN_MODEL / KNOWN_INPUT / KNOWN_OUTPUT updated to the new name and prices. - src/config.rs, src/db.rs, src/routes/sharing.rs: fixtures and catalog assertions updated; `config.rs` now also asserts that the retired names are gone and that `deepseek-flash` is a vision model. - docs/plan-api-matrix.md: stop hardcoding the catalogue size (point at the single source of truth instead). - ui/index.html: data.js cache-bust. Deployment note: `seed_models` is a full sync - `config`'s `[[models]]` is authoritative and rows absent from it are deleted at startup - so a deployment must apply the same rename to its own (gitignored) config.toml and restart. Tests: `cargo test` 239 passed / 0 failed (the count is unchanged - no test was added or removed, the catalogue assertions were updated in place); `cargo fmt --check` exit 0. Clippy is clean on CI's stable toolchain (main's last run: "Run clippy" success). The only complete toolchain installable in this sandbox is rustc/clippy 1.95.0, whose clippy additionally flags one pre-existing `collapsible_match` in `src/protocol.rs:662` - a file this change does not touch (it landed in #207 and its CI has been green since), so it is left alone rather than fixed opportunistically here. --- config/config.example.toml | 40 ++++++++++++++------------------------ docs/plan-api-matrix.md | 2 +- src/catalog_gate.rs | 12 ++++++------ src/config.rs | 26 +++++++++++++++++++------ src/db.rs | 14 ++++++------- src/routes/sharing.rs | 24 +++++++++++------------ ui/index.html | 2 +- ui/js/data.js | 5 ++--- 8 files changed, 64 insertions(+), 61 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index d9a8d15..b77eaba 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -229,24 +229,27 @@ endpoints = [ # 高峰时段价(rant 2026-08-20T11:58:40):peak_input_per_m / peak_output_per_m / # peak_cache_hit_input_per_m 三个可选字段,缺省 0 = 不启用高峰计费(沿用空闲价)。 # 命中高峰时段(北京时间 9-12、14-18,周一至周日)时按高峰价扣点。 -# DeepSeek 为官方价(2026-08-20 浏览器核实):空闲价即高峰价的一半, -# 高峰 9-12/14-18 北京时翻倍(flash 3.0/0.10/9.0,pro 9.0/0.30/27.0 元/M)。 +# DeepSeek 为官方价(2026-09-14 浏览器核实,https://api-docs.deepseek.com/zh-cn/quick_start/pricing): +# 空闲价即高峰价的一半,高峰 9-12/14-18 北京时翻倍(flash 2.0/0.04/8.0,pro 9.0/0.30/27.0 元/M)。 +# 模型名同样以官方文档为准:V4.1-Flash 的模型名是 `deepseek-flash`(V4 Flash 与 V4 Flash-Vision-Exp +# 已下线,旧名请求被官方路由到 V4.1-Flash 并按 Flash 价计费 ⇒ 目录中不再单列那两个旧名)。 # ============================================================ [[models]] provider = "deepseek" -model = "deepseek-v4-flash" +model = "deepseek-flash" currency = "CNY" -input_per_m = 1.5 -cache_hit_input_per_m = 0.05 -output_per_m = 4.5 +input_per_m = 1.0 +cache_hit_input_per_m = 0.02 +output_per_m = 4.0 # 高峰时段价(北京 9-12 / 14-18 翻倍;官方价) -peak_input_per_m = 3.0 -peak_cache_hit_input_per_m = 0.10 -peak_output_per_m = 9.0 +peak_input_per_m = 2.0 +peak_cache_hit_input_per_m = 0.04 +peak_output_per_m = 8.0 context_length = 1048576 max_output = 384000 -vision = false +# DeepSeek-V4.1-Flash 原生多模态(官方「图像理解:支持」)⇒ 旧 vision-exp 条目已并入本条 +vision = true [[models]] provider = "deepseek" @@ -379,18 +382,5 @@ context_length = 1048576 max_output = 0 vision = false -# DeepSeek 视觉模型:价格与 deepseek-v4-flash 完全相同(读图能力增强) -[[models]] -provider = "deepseek" -model = "deepseek-v4-flash-vision-exp" -currency = "CNY" -input_per_m = 1.5 -cache_hit_input_per_m = 0.05 -output_per_m = 4.5 -# 高峰时段价(北京 9-12 / 14-18 翻倍;与 flash 一致) -peak_input_per_m = 3.0 -peak_cache_hit_input_per_m = 0.10 -peak_output_per_m = 9.0 -context_length = 1048576 -max_output = 384000 -vision = true +# 读图模型:DeepSeek 的视觉能力已并入 `deepseek-flash`(V4.1-Flash 原生多模态), +# 旧的 `deepseek-v4-flash-vision-exp` 已下线并被官方路由到 V4.1-Flash ⇒ 此处不再单列。 diff --git a/docs/plan-api-matrix.md b/docs/plan-api-matrix.md index 25e8ad6..e21a540 100644 --- a/docs/plan-api-matrix.md +++ b/docs/plan-api-matrix.md @@ -32,4 +32,4 @@ Base URL 统一由 AITokenPool 提供(`[server].public_url` 配置),设置 ## 4. 模型目录 -当前内置 14 个模型(DeepSeek / GLM / GPT / Claude / Gemini / 豆包 / MiniMax / 通义等),含 context window、vision 支持、缓存价与高峰价字段(数量与明细以 `config/config.example.toml` 的 `[[models]]` 为唯一真源,由 `src/catalog_gate.rs` 的 `MODEL_COUNT` 守卫)。模型列表可经管理端「模型管理」页 CRUD(需 admin 角色)。 +内置 DeepSeek / GLM / GPT / Claude / Gemini / 豆包 / MiniMax / 通义等模型,含 context window、vision 支持、缓存价与高峰价字段。**数量与明细以 `config/config.example.toml` 的 `[[models]]` 为唯一真源**(由 `src/catalog_gate.rs` 的 `MODEL_COUNT` 守卫,此处不抄写数字以免随之陈旧)。模型列表可经管理端「模型管理」页 CRUD(需 admin 角色)。 diff --git a/src/catalog_gate.rs b/src/catalog_gate.rs index da228ed..8481b09 100644 --- a/src/catalog_gate.rs +++ b/src/catalog_gate.rs @@ -32,14 +32,14 @@ const CONFIG_TOML: &str = include_str!("../config/config.example.toml"); /// /// 它们的作用是把「提取器静默失真」与「数据真的变了」区分开:若扫描器写错而返回空集, /// 集合断言会**在空集上"通过"**(C2005 坑 68),这些计数会先把运行中止。 -const MODEL_COUNT: usize = 14; +const MODEL_COUNT: usize = 13; const MARKET_COUNT: usize = 7; const PLAN_COUNT: usize = 12; /// 已知真值(从配置里读出的官方价,CNY 计价)——用于确认解析器真的读到了正确字段。 -const KNOWN_MODEL: &str = "deepseek-v4-flash"; -const KNOWN_INPUT: f64 = 1.5; -const KNOWN_OUTPUT: f64 = 4.5; +const KNOWN_MODEL: &str = "deepseek-flash"; +const KNOWN_INPUT: f64 = 1.0; +const KNOWN_OUTPUT: f64 = 4.0; /// 价格比较的容差。两侧都由十进制字面量解析而来,实际是精确相等; /// 留一个极小容差只为避免浮点表示差异造成的假红。 @@ -447,7 +447,7 @@ mod tests { /// /// 双向是关键,且两个方向对应两类真实事故: /// - 「兜底多出来的」= 幽灵模型(`ce6d0db` 塞进 `gemini-3.5-flash-lite`); - /// - 「兜底缺失的」= 新增模型忘了同步(`deepseek-v4-flash-vision-exp`)。 + /// - 「兜底缺失的」= 新增模型忘了同步(`ce6d0db` 之后新增 `deepseek-flash` 时)。 /// /// 只查一个方向会漏掉其中一类(C2010 更正:此前我误以为该断言应为「子集」)。 #[test] @@ -562,7 +562,7 @@ mod tests { "阴性对照失败:MARKET 中的改名残留未被报出" ); - // ④ 错价(真实事故形态:旧的 flash 价格 1.008/2.016) + // ④ 错价(真实事故形态:旧的 DeepSeek flash 价格 1.5/4.5,官方已于 2026-09-10 下调为 1.0/4.0) let mut wrong = js_models.get(KNOWN_MODEL).cloned().unwrap(); wrong.input = 1.008; wrong.output = 2.016; diff --git a/src/config.rs b/src/config.rs index 993b186..b727dec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -338,12 +338,26 @@ mod tests { let flash = cfg .models .iter() - .find(|m| m.model == "deepseek-v4-flash") - .unwrap(); - assert_eq!(flash.input_per_m, 1.5); - assert_eq!(flash.cache_hit_input_per_m, 0.05); - assert_eq!(flash.peak_input_per_m, 3.0); - assert_eq!(flash.peak_output_per_m, 9.0); + .find(|m| m.model == "deepseek-flash") + .expect("deepseek-flash(V4.1-Flash,官方 2026-09-14 的现名)应在模型目录中"); + assert_eq!(flash.input_per_m, 1.0); + assert_eq!(flash.cache_hit_input_per_m, 0.02); + assert_eq!(flash.output_per_m, 4.0); + assert_eq!(flash.peak_input_per_m, 2.0); + assert_eq!(flash.peak_cache_hit_input_per_m, 0.04); + assert_eq!(flash.peak_output_per_m, 8.0); + assert!( + flash.vision, + "V4.1-Flash 原生多模态(官方「图像理解:支持」)" + ); + // 已下线的旧名不得再出现在目录中:市场列的是「现在能买的模型」 + // (官方:deepseek-v4-flash / deepseek-v4-flash-vision-exp「对应模型已下线」) + assert!( + cfg.models.iter().all( + |m| m.model != "deepseek-v4-flash" && m.model != "deepseek-v4-flash-vision-exp" + ), + "已下线的 DeepSeek 旧模型名不应留在模型目录中" + ); // 未配置高峰价的模型 → 缺省 0(不启用高峰计费) let zhipu = cfg.models.iter().find(|m| m.provider == "zhipu").unwrap(); assert_eq!(zhipu.peak_input_per_m, 0.0, "无高峰价字段 → 缺省 0"); diff --git a/src/db.rs b/src/db.rs index 8c6c200..60061ed 100644 --- a/src/db.rs +++ b/src/db.rs @@ -463,7 +463,7 @@ pub(crate) fn seed_test_users(conn: &Connection) -> Result<()> { if key_count == 0 { conn.execute( "INSERT INTO keys (provider, plan, model, status, owner_id, encrypted_key, quota, used) \ - VALUES ('deepseek', 'deepseek-paygo', 'deepseek-v4-flash', 'on', ?1, 'sk-placeholder-encrypted', 1000, 0)", + VALUES ('deepseek', 'deepseek-paygo', 'deepseek-flash', 'on', ?1, 'sk-placeholder-encrypted', 1000, 0)", [demo_id], )?; } @@ -924,19 +924,19 @@ mod tests { "peak cache_hit={peak_cache}" ); assert_eq!(currency, "CNY"); - // flash 也在(config 直接定义;高峰 3.0 / 9.0 / 0.10) + // deepseek-flash(V4.1-Flash)也在(config 直接定义;高峰 2.0 / 8.0 / 0.04) let (fi, fh, fp_in, fp_out): (f64, f64, f64, f64) = conn .query_row( "SELECT input_per_m, cache_hit_input_per_m, peak_input_per_m, peak_output_per_m \ - FROM models WHERE provider = 'deepseek' AND model = 'deepseek-v4-flash'", + FROM models WHERE provider = 'deepseek' AND model = 'deepseek-flash'", [], |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?)), ) .unwrap(); - assert!((fi - 1.5).abs() < 1e-9, "flash input={fi}"); - assert!((fh - 0.05).abs() < 1e-9, "flash cache_hit={fh}"); - assert!((fp_in - 3.0).abs() < 1e-9, "flash peak input={fp_in}"); - assert!((fp_out - 9.0).abs() < 1e-9, "flash peak output={fp_out}"); + assert!((fi - 1.0).abs() < 1e-9, "flash input={fi}"); + assert!((fh - 0.02).abs() < 1e-9, "flash cache_hit={fh}"); + assert!((fp_in - 2.0).abs() < 1e-9, "flash peak input={fp_in}"); + assert!((fp_out - 8.0).abs() < 1e-9, "flash peak output={fp_out}"); // 无高峰价的模型 → peak 缺省 0(不启用高峰计费) let (z_in, z_cache, z_out): (f64, f64, f64) = conn .query_row( diff --git a/src/routes/sharing.rs b/src/routes/sharing.rs index 8ebea0c..61b5870 100644 --- a/src/routes/sharing.rs +++ b/src/routes/sharing.rs @@ -358,7 +358,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-realsecret1234","quota":1000,"available":{"days":[1,2,3,4,5],"start":"09:00","end":"18:00"},"note":"工作日共享"}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-realsecret1234","quota":1000,"available":{"days":[1,2,3,4,5],"start":"09:00","end":"18:00"},"note":"工作日共享"}"#), &key, ) .await; @@ -414,7 +414,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-patchme9999"}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-patchme9999"}"#), &key, ) .await; @@ -492,7 +492,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-created1234","used":0,"note":"utc"}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-created1234","used":0,"note":"utc"}"#), &key, ) .await; @@ -580,7 +580,7 @@ mod tests { st, "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"aa中中中中中","quota":1000,"available":{"days":[1],"start":"09:00","end":"18:00"}}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"aa中中中中中","quota":1000,"available":{"days":[1],"start":"09:00","end":"18:00"}}"#), &token, ) .await; @@ -614,7 +614,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"WRONG","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-wrong1234","quota":100}"#), + Some(r#"{"provider":"WRONG","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-wrong1234","quota":100}"#), &key, ) .await; @@ -639,7 +639,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-control1234","quota":100}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-control1234","quota":100}"#), &key, ) .await; @@ -676,7 +676,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"no-such-plan","model":"deepseek-v4-flash","key":"sk-phantom1111","quota":100}"#), + Some(r#"{"provider":"deepseek","plan":"no-such-plan","model":"deepseek-flash","key":"sk-phantom1111","quota":100}"#), &key, ) .await; @@ -687,7 +687,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","model":"deepseek-v4-flash","key":"sk-noplan2222","quota":100}"#), + Some(r#"{"provider":"deepseek","model":"deepseek-flash","key":"sk-noplan2222","quota":100}"#), &key, ) .await; @@ -701,7 +701,7 @@ mod tests { st.clone(), "POST", "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/api/sharings", - Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-v4-flash","key":"sk-control3333","quota":100}"#), + Some(r#"{"provider":"deepseek","plan":"deepseek-paygo","model":"deepseek-flash","key":"sk-control3333","quota":100}"#), &key, ) .await; @@ -714,8 +714,8 @@ mod tests { crate::dao::list_models_with_availability(&conn) .unwrap() .iter() - .find(|m| m["model"] == "deepseek-v4-flash") - .expect("市场列表应含 deepseek-v4-flash")["available_keys"] + .find(|m| m["model"] == "deepseek-flash") + .expect("市场列表应含 deepseek-flash")["available_keys"] .as_i64() .unwrap() }; @@ -724,7 +724,7 @@ mod tests { let conn = st.db.lock().unwrap(); conn.execute( "INSERT INTO keys (provider, plan, model, status, owner_id, encrypted_key, quota, used) \ - VALUES ('deepseek', 'no-such-plan', 'deepseek-v4-flash', 'on', 1, 'sk-legacy-enc', 100, 0)", + VALUES ('deepseek', 'no-such-plan', 'deepseek-flash', 'on', 1, 'sk-legacy-enc', 100, 0)", [], ) .unwrap(); diff --git a/ui/index.html b/ui/index.html index 3f98d7b..469a1ce 100644 --- a/ui/index.html +++ b/ui/index.html @@ -843,7 +843,7 @@

使用模型

- + diff --git a/ui/js/data.js b/ui/js/data.js index ad9ca48..4147b74 100644 --- a/ui/js/data.js +++ b/ui/js/data.js @@ -17,8 +17,7 @@ // 模型价格(对齐 config.toml [[models]] 官方价,折算为点数 / 1M tokens)——上架表单定价兜底 const MODELS = [ { provider: "deepseek", model: "deepseek-v4-pro", in: CNY(4.5), out: CNY(13.5), ctx: 1048576, max: 384000, tag: "推理" }, - { provider: "deepseek", model: "deepseek-v4-flash", in: CNY(1.5), out: CNY(4.5), ctx: 1048576, max: 384000, tag: "通用" }, - { provider: "deepseek", model: "deepseek-v4-flash-vision-exp", in: CNY(1.5), out: CNY(4.5), ctx: 1048576, max: 384000, tag: "读图" }, + { provider: "deepseek", model: "deepseek-flash", in: CNY(1.0), out: CNY(4.0), ctx: 1048576, max: 384000, tag: "多模态" }, { provider: "zhipu", model: "glm-5.3", in: CNY(8.0), out: CNY(28.0), ctx: 1048576, max: 131072, tag: "旗舰" }, { provider: "openai", model: "gpt-5.6-sol", in: USD(5.0), out: USD(30.0), ctx: 1050000, max: null, tag: "旗舰" }, { provider: "anthropic",model: "claude-opus-5", in: USD(5.0), out: USD(25.0), ctx: 1000000, max: null, tag: "旗舰" }, @@ -79,7 +78,7 @@ // 市场在售 key(游客浏览用;rant 2026-08-19T15:54:06:multi/success 为虚构数据已移除; // 登录态用 GET /api/models 真实数据,multi=available_keys>=2、ctx=context_window) MARKET: [ - { id: 1, provider: "deepseek", model: "deepseek-v4-flash", in: CNY(1.5), out: CNY(4.5), ctx: 1048576, avail: true, peak: true, peakIn: CNY(3.0), peakOut: CNY(9.0), peakMult: 2 }, + { id: 1, provider: "deepseek", model: "deepseek-flash", in: CNY(1.0), out: CNY(4.0), ctx: 1048576, avail: true, peak: true, peakIn: CNY(2.0), peakOut: CNY(8.0), peakMult: 2 }, { id: 2, provider: "zhipu", model: "glm-5.3", in: CNY(8.0), out: CNY(28.0), ctx: 1048576, avail: true }, { id: 3, provider: "openai", model: "gpt-5.6-sol", in: USD(5.0), out: USD(30.0), ctx: 1050000, avail: true }, { id: 4, provider: "anthropic",model: "claude-opus-5", in: USD(5.0), out: USD(25.0), ctx: 1000000, avail: false },