Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 15 additions & 25 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 ⇒ 此处不再单列。
2 changes: 1 addition & 1 deletion docs/plan-api-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 角色)。
12 changes: 6 additions & 6 deletions src/catalog_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// 价格比较的容差。两侧都由十进制字面量解析而来,实际是精确相等;
/// 留一个极小容差只为避免浮点表示差异造成的假红。
Expand Down Expand Up @@ -447,7 +447,7 @@ mod tests {
///
/// 双向是关键,且两个方向对应两类真实事故:
/// - 「兜底多出来的」= 幽灵模型(`ce6d0db` 塞进 `gemini-3.5-flash-lite`);
/// - 「兜底缺失的」= 新增模型忘了同步(`deepseek-v4-flash-vision-exp`)。
/// - 「兜底缺失的」= 新增模型忘了同步(`ce6d0db` 之后新增 `deepseek-flash` 时)。
///
/// 只查一个方向会漏掉其中一类(C2010 更正:此前我误以为该断言应为「子集」)。
#[test]
Expand Down Expand Up @@ -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;
Expand Down
26 changes: 20 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
14 changes: 7 additions & 7 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
)?;
}
Expand Down Expand Up @@ -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(
Expand Down
24 changes: 12 additions & 12 deletions src/routes/sharing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand Down Expand Up @@ -414,7 +414,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand Down Expand Up @@ -492,7 +492,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand Down Expand Up @@ -580,7 +580,7 @@ mod tests {
st,
"POST",
"/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;
Expand Down Expand Up @@ -614,7 +614,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand All @@ -639,7 +639,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand Down Expand Up @@ -676,7 +676,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand All @@ -687,7 +687,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand All @@ -701,7 +701,7 @@ mod tests {
st.clone(),
"POST",
"/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;
Expand All @@ -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()
};
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ <h3 id="chat-title">使用模型</h3>
</div>

<script src="js/api.js?v=20260912-5"></script>
<script src="js/data.js?v=20260912-5"></script>
<script src="js/data.js?v=20260914-1"></script>
<script src="js/i18n.js?v=20260914-4"></script>
<script src="js/app.js?v=20260914-9"></script>
</body>
Expand Down
5 changes: 2 additions & 3 deletions ui/js/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: "旗舰" },
Expand Down Expand Up @@ -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 },
Expand Down
Loading