mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-15 23:22:59 +08:00
Merge pull request #8078 from feeeei/feat/gemini-4-argon-pricing
feat(gemini): 补齐 Gemini 4 Argon 计费
This commit is contained in:
@@ -524,6 +524,27 @@ func (s *BillingService) initFallbackPricing() {
|
||||
SupportsCacheBreakdown: false,
|
||||
}
|
||||
|
||||
// Gemini 4 Argon (Google AI pricing: $2 input / $10 output / $0.10 cached
|
||||
// input per MTok, promotional through 2026-11-30; official rates double to
|
||||
// $4/$20/$0.20 from 2026-12-01). One rate covers every prompt length.
|
||||
// Antigravity's -high/-low/-medium aliases are matched below so unavailable
|
||||
// remote pricing never records token-bearing requests at $0.
|
||||
s.fallbackPrices["gemini-4-argon"] = &ModelPricing{
|
||||
InputPricePerToken: 2e-6,
|
||||
OutputPricePerToken: 10e-6,
|
||||
CacheReadPricePerToken: 0.1e-6,
|
||||
SupportsCacheBreakdown: false,
|
||||
}
|
||||
|
||||
// Gemini 4 Argon Cyber Permissive (Vertex AI pricing: $4 input / $20 output /
|
||||
// $0.20 cached input per MTok). The Gemini 4 Argon promotion does not apply.
|
||||
s.fallbackPrices["gemini-4-argon-cyber-permissive"] = &ModelPricing{
|
||||
InputPricePerToken: 4e-6,
|
||||
OutputPricePerToken: 20e-6,
|
||||
CacheReadPricePerToken: 0.2e-6,
|
||||
SupportsCacheBreakdown: false,
|
||||
}
|
||||
|
||||
// OpenAI GPT-5.4(业务指定价格)
|
||||
s.fallbackPrices["gpt-5.4"] = &ModelPricing{
|
||||
InputPricePerToken: 2.5e-6, // $2.5 per MTok
|
||||
@@ -1082,6 +1103,13 @@ func (s *BillingService) getFallbackPricing(model string) *ModelPricing {
|
||||
if strings.Contains(modelLower, "gemini-3.8-flash") || strings.Contains(modelLower, "gemini-3-8-flash") {
|
||||
return s.fallbackPrices["gemini-3.8-flash"]
|
||||
}
|
||||
// Cyber 变体不享受 Gemini 4 Argon 的优惠价,必须先于 "gemini-4-argon" 判。
|
||||
if strings.Contains(modelLower, "gemini-4-argon-cyber") {
|
||||
return s.fallbackPrices["gemini-4-argon-cyber-permissive"]
|
||||
}
|
||||
if strings.Contains(modelLower, "gemini-4-argon") {
|
||||
return s.fallbackPrices["gemini-4-argon"]
|
||||
}
|
||||
|
||||
// DeepSeek 系列:官方模型 V4 Pro/Flash(含 vision-exp)按各自价卡;
|
||||
// 其余 deepseek-*(含已停服的 deepseek-chat / deepseek-reasoner 与未知型号)
|
||||
|
||||
@@ -43,7 +43,10 @@ func TestBuiltinGeminiCacheStoragePrice(t *testing.T) {
|
||||
{"gemini-flash-latest", 1e-6},
|
||||
{"gemini-flash-lite-latest", 1e-6},
|
||||
{"gemini-pro-latest", 4.5e-6},
|
||||
// 无存储价
|
||||
// 无存储价(Gemini 4 Argon 仅支持隐式缓存)
|
||||
{"gemini-4-argon", 0},
|
||||
{"gemini-4-argon-high", 0},
|
||||
{"gemini-4-argon-cyber-permissive", 0},
|
||||
{"gemini-embedding-001", 0},
|
||||
{"gemini-unknown-model", 0},
|
||||
{"claude-sonnet-5-5", 0},
|
||||
|
||||
@@ -1306,7 +1306,7 @@ func (s *PricingService) buildModelLookupCandidates(modelLower string) []string
|
||||
normalized := normalizeModelNameForPricing(modelLower)
|
||||
|
||||
// A tier-specific entry should take precedence when the pricing catalog gains
|
||||
// one later. Antigravity's Gemini Flash thinking tiers share the base rate,
|
||||
// one later. Antigravity's Gemini thinking tiers share the base rate,
|
||||
// so the normalized base remains the fallback after the exact aliases.
|
||||
candidates := rawCandidates
|
||||
if normalizeGeminiThinkingTierAlias(lastSegment(modelLower)) != lastSegment(modelLower) {
|
||||
@@ -1368,12 +1368,12 @@ func normalizeModelNameForPricing(model string) string {
|
||||
return normalizeGeminiThinkingTierAlias(model)
|
||||
}
|
||||
|
||||
// normalizeGeminiThinkingTierAlias maps Antigravity's Gemini Flash
|
||||
// thinking-tier model IDs to the public base model. The tier controls reasoning
|
||||
// behavior, not the published token rate, so this keeps -high/-low/-medium and
|
||||
// -tiered requests on the corresponding base model's price card.
|
||||
// normalizeGeminiThinkingTierAlias maps Antigravity's Gemini thinking-tier
|
||||
// model IDs to the public base model. The tier controls reasoning behavior, not
|
||||
// the published token rate, so this keeps -high/-low/-medium and -tiered
|
||||
// requests on the corresponding base model's price card.
|
||||
func normalizeGeminiThinkingTierAlias(model string) string {
|
||||
for _, baseModel := range []string{"gemini-3.6-flash", "gemini-3.7-flash", "gemini-3.8-flash"} {
|
||||
for _, baseModel := range []string{"gemini-3.6-flash", "gemini-3.7-flash", "gemini-3.8-flash", "gemini-4-argon"} {
|
||||
for _, tier := range []string{"-high", "-low", "-medium", "-tiered"} {
|
||||
if model == baseModel+tier {
|
||||
return baseModel
|
||||
|
||||
@@ -732,6 +732,93 @@ func TestDefaultPricingIncludesGemini36FlashRates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPricingService_Gemini4ArgonThinkingTiersUseBasePricing(t *testing.T) {
|
||||
basePricing := &LiteLLMModelPricing{InputCostPerToken: 2e-6, OutputCostPerToken: 10e-6, CacheReadInputTokenCost: 0.1e-6}
|
||||
cyberPricing := &LiteLLMModelPricing{InputCostPerToken: 4e-6, OutputCostPerToken: 20e-6, CacheReadInputTokenCost: 0.2e-6}
|
||||
svc := &PricingService{pricingData: map[string]*LiteLLMModelPricing{
|
||||
"gemini-4-argon": basePricing,
|
||||
"gemini-4-argon-cyber-permissive": cyberPricing,
|
||||
}}
|
||||
|
||||
for _, model := range []string{
|
||||
"gemini-4-argon",
|
||||
"gemini-4-argon-high",
|
||||
"gemini-4-argon-low",
|
||||
"gemini-4-argon-medium",
|
||||
"models/gemini-4-argon-high",
|
||||
"projects/p/locations/global/publishers/google/models/gemini-4-argon",
|
||||
} {
|
||||
t.Run(model, func(t *testing.T) {
|
||||
require.Same(t, basePricing, svc.GetModelPricing(model))
|
||||
})
|
||||
}
|
||||
require.Same(t, cyberPricing, svc.GetModelPricing("gemini-4-argon-cyber-permissive"))
|
||||
}
|
||||
|
||||
func TestBillingService_Gemini4ArgonFallbacksAreBillable(t *testing.T) {
|
||||
svc := NewBillingService(&config.Config{}, nil)
|
||||
tokens := UsageTokens{InputTokens: 1_000_000, OutputTokens: 1_000_000, CacheReadTokens: 1_000_000}
|
||||
|
||||
for _, tc := range []struct {
|
||||
model string
|
||||
input, output, read float64
|
||||
}{
|
||||
{"gemini-4-argon", 2, 10, 0.1},
|
||||
{"gemini-4-argon-high", 2, 10, 0.1},
|
||||
{"gemini-4-argon-low", 2, 10, 0.1},
|
||||
{"gemini-4-argon-medium", 2, 10, 0.1},
|
||||
{"models/gemini-4-argon", 2, 10, 0.1},
|
||||
{"gemini-4-argon-cyber-permissive", 4, 20, 0.2},
|
||||
{"gemini-4-argon-cyber", 4, 20, 0.2},
|
||||
{"publishers/google/models/gemini-4-argon-cyber-permissive", 4, 20, 0.2},
|
||||
} {
|
||||
t.Run(tc.model, func(t *testing.T) {
|
||||
cost, err := svc.CalculateCost(tc.model, tokens, 1)
|
||||
require.NoError(t, err)
|
||||
require.InDelta(t, tc.input, cost.InputCost, 1e-12)
|
||||
require.InDelta(t, tc.output, cost.OutputCost, 1e-12)
|
||||
require.InDelta(t, tc.read, cost.CacheReadCost, 1e-12)
|
||||
require.InDelta(t, tc.input+tc.output+tc.read, cost.TotalCost, 1e-12)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultPricingIncludesGemini4ArgonRates(t *testing.T) {
|
||||
data, err := os.ReadFile(filepath.Join("..", "..", "resources", "model-pricing", "model_prices_and_context_window.json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
pricingSvc := &PricingService{}
|
||||
pricingData, err := pricingSvc.parsePricingData(data)
|
||||
require.NoError(t, err)
|
||||
pricingSvc.pricingData = pricingData
|
||||
|
||||
for _, tc := range []struct {
|
||||
model string
|
||||
provider string
|
||||
input, output, read float64
|
||||
}{
|
||||
{"gemini-4-argon", "gemini", 2e-6, 10e-6, 0.1e-6},
|
||||
{"gemini-4-argon-high", "gemini", 2e-6, 10e-6, 0.1e-6},
|
||||
{"gemini-4-argon-cyber-permissive", "vertex_ai-language-models", 4e-6, 20e-6, 0.2e-6},
|
||||
} {
|
||||
t.Run(tc.model, func(t *testing.T) {
|
||||
pricing := pricingSvc.GetModelPricing(tc.model)
|
||||
require.NotNil(t, pricing)
|
||||
require.Equal(t, tc.provider, pricing.LiteLLMProvider)
|
||||
require.InDelta(t, tc.input, pricing.InputCostPerToken, 1e-15)
|
||||
require.InDelta(t, tc.output, pricing.OutputCostPerToken, 1e-15)
|
||||
require.InDelta(t, tc.read, pricing.CacheReadInputTokenCost, 1e-15)
|
||||
// Priority 档为标准价的 1.8 倍;单一价档不分提示词长度,显式缓存不可用故无存储价。
|
||||
require.InDelta(t, tc.input*1.8, pricing.InputCostPerTokenPriority, 1e-15)
|
||||
require.InDelta(t, tc.output*1.8, pricing.OutputCostPerTokenPriority, 1e-15)
|
||||
require.InDelta(t, tc.read*1.8, pricing.CacheReadInputTokenCostPriority, 1e-15)
|
||||
require.Zero(t, pricing.LongContextInputTokenThreshold)
|
||||
require.Zero(t, pricing.CacheStorageCostPerTokenPerHour)
|
||||
})
|
||||
}
|
||||
require.Contains(t, pricingSvc.ListModelNamesByProvider("gemini"), "gemini-4-argon")
|
||||
}
|
||||
|
||||
func TestDefaultPricingUsesCurrentCodexAutoReviewBaseRates(t *testing.T) {
|
||||
data, err := os.ReadFile(filepath.Join("..", "..", "resources", "model-pricing", "model_prices_and_context_window.json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -2666,6 +2666,40 @@
|
||||
"supports_reasoning": true,
|
||||
"supports_service_tier": true
|
||||
},
|
||||
"gemini-4-argon": {
|
||||
"cache_read_input_token_cost": 1e-07,
|
||||
"cache_read_input_token_cost_priority": 1.8e-07,
|
||||
"input_cost_per_token": 2e-06,
|
||||
"input_cost_per_token_priority": 3.6e-06,
|
||||
"litellm_provider": "gemini",
|
||||
"max_input_tokens": 1048576,
|
||||
"max_output_tokens": 65536,
|
||||
"max_tokens": 65536,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1e-05,
|
||||
"output_cost_per_token_priority": 1.8e-05,
|
||||
"source": "https://ai.google.dev/gemini-api/docs/pricing",
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_service_tier": true
|
||||
},
|
||||
"gemini-4-argon-cyber-permissive": {
|
||||
"cache_read_input_token_cost": 2e-07,
|
||||
"cache_read_input_token_cost_priority": 3.6e-07,
|
||||
"input_cost_per_token": 4e-06,
|
||||
"input_cost_per_token_priority": 7.2e-06,
|
||||
"litellm_provider": "vertex_ai-language-models",
|
||||
"max_input_tokens": 1048576,
|
||||
"max_output_tokens": 65536,
|
||||
"max_tokens": 65536,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 2e-05,
|
||||
"output_cost_per_token_priority": 3.6e-05,
|
||||
"source": "https://cloud.google.com/gemini-enterprise-agent-platform/generative-ai/pricing",
|
||||
"supports_prompt_caching": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_service_tier": true
|
||||
},
|
||||
"gemini-embedding-001": {
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"litellm_provider": "vertex_ai-embedding-models",
|
||||
|
||||
Reference in New Issue
Block a user