fix: support Gemini billing route mapping and pricing update

This commit is contained in:
Ivan Miao 2026-07-07 09:25:07 +02:00 committed by Teknium
parent ee1e789877
commit ecebff82d2
2 changed files with 82 additions and 8 deletions

View file

@ -511,15 +511,53 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
pricing_version="deepseek-pricing-2026-07",
),
# Google Gemini
(
"google",
"gemini-3.5-flash",
): PricingEntry(
input_cost_per_million=Decimal("1.50"),
output_cost_per_million=Decimal("9.00"),
cache_read_cost_per_million=Decimal("0.15"),
cache_write_cost_per_million=Decimal("1.50"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-07-07",
),
(
"google",
"gemini-3.1-pro",
): PricingEntry(
input_cost_per_million=Decimal("2.00"),
output_cost_per_million=Decimal("12.00"),
cache_read_cost_per_million=Decimal("0.20"),
cache_write_cost_per_million=Decimal("2.00"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-07-07",
),
(
"google",
"gemini-3.1-flash-lite",
): PricingEntry(
input_cost_per_million=Decimal("0.25"),
output_cost_per_million=Decimal("1.50"),
cache_read_cost_per_million=Decimal("0.025"),
cache_write_cost_per_million=Decimal("0.25"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-07-07",
),
(
"google",
"gemini-2.5-pro",
): PricingEntry(
input_cost_per_million=Decimal("1.25"),
output_cost_per_million=Decimal("10.00"),
cache_read_cost_per_million=Decimal("0.125"),
cache_write_cost_per_million=Decimal("1.25"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-03-16",
pricing_version="google-pricing-2026-07-07",
),
(
"google",
@ -527,9 +565,11 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
): PricingEntry(
input_cost_per_million=Decimal("0.15"),
output_cost_per_million=Decimal("0.60"),
cache_read_cost_per_million=Decimal("0.015"),
cache_write_cost_per_million=Decimal("0.15"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-03-16",
pricing_version="google-pricing-2026-07-07",
),
(
"google",
@ -537,9 +577,11 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
): PricingEntry(
input_cost_per_million=Decimal("0.10"),
output_cost_per_million=Decimal("0.40"),
cache_read_cost_per_million=Decimal("0.01"),
cache_write_cost_per_million=Decimal("0.10"),
source="official_docs_snapshot",
source_url="https://ai.google.dev/pricing",
pricing_version="google-pricing-2026-03-16",
pricing_version="google-pricing-2026-07-07",
),
# AWS Bedrock — pricing per the Bedrock pricing page.
# Bedrock charges the same per-token rates as the model provider but
@ -925,11 +967,17 @@ def resolve_billing_route(
return BillingRoute(provider="openai", model=model.split("/")[-1], base_url=base_url or "", billing_mode="official_docs_snapshot")
if provider_name in {"minimax", "minimax-cn"}:
return BillingRoute(provider=provider_name, model=model.split("/")[-1], base_url=base_url or "", billing_mode="official_docs_snapshot")
# Vertex AI hosts the same Gemini models as Google AI Studio; price them
# off the gemini official-docs snapshot. Strip the "google/" vendor prefix
# the OpenAI-compat endpoint requires so the pricing key matches.
if provider_name == "vertex" or base_url_host_matches(base_url or "", "aiplatform.googleapis.com"):
return BillingRoute(provider="gemini", model=model.split("/")[-1], base_url=base_url or "", billing_mode="official_docs_snapshot")
# Google AI Studio (Gemini) and Vertex AI host the same Gemini models.
# Price them off the official docs snapshot — the pricing keys are
# keyed on provider='google', so normalize every Google-flavored
# provider name/host onto it. Strip the "google/" vendor prefix the
# Vertex OpenAI-compat endpoint requires so the pricing key matches.
if (
provider_name in {"google", "gemini", "vertex", "google-gemini", "google-ai-studio", "google-vertex", "vertex-ai"}
or base_url_host_matches(base_url or "", "aiplatform.googleapis.com")
or base_url_host_matches(base_url or "", "generativelanguage.googleapis.com")
):
return BillingRoute(provider="google", model=model.split("/")[-1], base_url=base_url or "", billing_mode="official_docs_snapshot")
if provider_name == "fireworks" or base_url_host_matches(base_url or "", "api.fireworks.ai"):
# Fireworks model ids look like accounts/fireworks/models/<name>;
# rsplit("/", 1)[-1] yields just <name> which is what the dict keys on.

View file

@ -636,3 +636,29 @@ def test_deepseek_v4_flash_estimate_usage_cost():
assert result.amount_usd is not None
# 1M input × $0.14/M + 500K output × $0.28/M = $0.14 + $0.14 = $0.28
assert float(result.amount_usd) == 0.28
def test_gemini_3_5_flash_pricing_resolved():
"""Ensure gemini-3.5-flash pricing exists and resolves correctly."""
entry = get_pricing_entry("gemini-3.5-flash", provider="google")
assert entry is not None
assert float(entry.input_cost_per_million) == 1.50
assert float(entry.output_cost_per_million) == 9.00
assert float(entry.cache_read_cost_per_million) == 0.15
assert float(entry.cache_write_cost_per_million) == 1.50
def test_gemini_provider_maps_to_google():
"""Ensure using 'gemini' as provider resolves to 'google' pricing."""
entry = get_pricing_entry("gemini-3.5-flash", provider="gemini")
assert entry is not None
assert float(entry.input_cost_per_million) == 1.50
# Also check base URL matching
entry_base = get_pricing_entry(
"gemini-3.5-flash",
provider="custom",
base_url="https://generativelanguage.googleapis.com/v1beta",
)
assert entry_base is not None
assert float(entry_base.input_cost_per_million) == 1.50