From ba5485a9be0d488b804b42dbb77d357ed12bd410 Mon Sep 17 00:00:00 2001 From: moranzhi Date: Thu, 15 Oct 2026 01:38:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=B7=E7=9B=AE=E5=AF=B9=E7=85=A7=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E4=BB=8D=E5=9C=A8=E9=A2=84=E8=A7=88=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E4=B8=93=E4=B8=9A=E6=A1=A3=EF=BC=8C=E4=BB=A5=E5=8F=8A=E9=9D=9E?= =?UTF-8?q?=E5=BF=AB=E9=97=AA=E3=80=81=E9=9D=9E=E4=B8=93=E4=B8=9A=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E5=8F=B7=E6=A1=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 否则当前在用的型号会被整档滤掉,统计对不上实际调用。 Co-authored-by: Cursor --- src/stats/pricing.ts | 8 +++++++- tests/pricing.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/stats/pricing.ts b/src/stats/pricing.ts index 4aa528f..46f8a4a 100644 --- a/src/stats/pricing.ts +++ b/src/stats/pricing.ts @@ -117,6 +117,7 @@ export function isOpenRouterModelsUrl(url: string): boolean { /** * 对比用的当前档:每个家族只留最新一档(DeepSeek / Claude / GLM / Gemini / GPT / Grok)。 + * Gemini 另留非 flash/pro 的代号档(如 gemini-4-argon);Pro 若只有 preview 也算当前档。 * 同一档有多个 id 时留 created 更新的那个。 */ export function usualOpenRouterBucket(modelId: string): string | null { @@ -132,7 +133,11 @@ export function usualOpenRouterBucket(modelId: string): string | null { return null; } const parts = name.split(/[^a-z0-9.]+/); - if (parts.some((part) => USUAL_SKIP_PARTS.has(part))) return null; + const skipped = parts.filter((part) => USUAL_SKIP_PARTS.has(part)); + // Gemini 当前 Pro 在 OpenRouter 上仍带 preview,不能整档丢掉。 + const geminiPreviewOnly = + name.includes("gemini") && skipped.length > 0 && skipped.every((part) => part === "preview"); + if (skipped.length && !geminiPreviewOnly) return null; if (name.includes("claude-haiku")) return "claude-haiku"; if (name.includes("claude-sonnet")) return "claude-sonnet"; if (name.includes("claude-opus")) return "claude-opus"; @@ -148,6 +153,7 @@ export function usualOpenRouterBucket(modelId: string): string | null { } if (name.includes("gemini") && name.includes("pro")) return "gemini-pro"; if (name.includes("gemini") && name.includes("flash")) return "gemini-flash"; + if (name.includes("gemini")) return "gemini"; if (name.startsWith("gpt-") && name.includes("luna-pro")) return "gpt-luna-pro"; if (name.startsWith("gpt-") && name.includes("luna")) return "gpt-luna"; if (name.startsWith("gpt-") && name.includes("sol-pro")) return "gpt-sol-pro"; diff --git a/tests/pricing.test.ts b/tests/pricing.test.ts index c13a033..78a40ad 100644 --- a/tests/pricing.test.ts +++ b/tests/pricing.test.ts @@ -255,6 +255,9 @@ describe("trimOpenRouterUsualCatalog", () => { ); expect(usualOpenRouterBucket("google/gemini-3.8-flash")).toBe("gemini-flash"); expect(usualOpenRouterBucket("google/gemini-2.5-pro")).toBe("gemini-pro"); + expect(usualOpenRouterBucket("google/gemini-3.1-pro-preview")).toBe("gemini-pro"); + expect(usualOpenRouterBucket("google/gemini-4-argon")).toBe("gemini"); + expect(usualOpenRouterBucket("google/gemini-3.5-flash-lite")).toBeNull(); expect(usualOpenRouterBucket("openai/gpt-4o:batch")).toBeNull(); const trimmed = JSON.parse( trimOpenRouterUsualCatalog( @@ -293,6 +296,39 @@ describe("trimOpenRouterUsualCatalog", () => { "anthropic/claude-haiku-5.5", "openai/gpt-6-luna", ]); + const gemini = JSON.parse( + trimOpenRouterUsualCatalog( + JSON.stringify({ + data: [ + { + id: "google/gemini-2.5-pro", + created: 10, + pricing: { prompt: "0.000001", completion: "0.000005" }, + }, + { + id: "google/gemini-3.1-pro-preview", + created: 20, + pricing: { prompt: "0.000002", completion: "0.000008" }, + }, + { + id: "google/gemini-3.8-flash", + created: 30, + pricing: { prompt: "0.0000003", completion: "0.000001" }, + }, + { + id: "google/gemini-4-argon", + created: 40, + pricing: { prompt: "0.000003", completion: "0.000012" }, + }, + ], + }), + ), + ) as { data: Array<{ id: string }> }; + expect(gemini.data.map((row) => row.id).sort()).toEqual([ + "google/gemini-3.1-pro-preview", + "google/gemini-3.8-flash", + "google/gemini-4-argon", + ]); const pinned = JSON.parse( trimOpenRouterUsualCatalog( JSON.stringify({