관리자 사용량 근거를 정교화

This commit is contained in:
Yun Chan 2026-08-29 23:59:17 +09:00
parent ccdcfcd2f5
commit 707dba4f8f
10 changed files with 1136 additions and 209 deletions

View file

@ -9,10 +9,14 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import date, datetime, timezone
MILLION = 1_000_000
RATE_CARD_VERSION = "2026-07-31"
GOOGLE_36_RELEASE_START = date(2026, 7, 21)
GOOGLE_FLASH_INTRO_START = date(2026, 8, 13)
GOOGLE_FLASH_INTRO_END = date(2027, 1, 1)
GOOGLE_PRICING_URL = "https://ai.google.dev/gemini-api/docs/pricing"
OPENAI_CODEX_RATE_URL = "https://help.openai.com/en/articles/20001106-codex-rate-card"
@ -40,11 +44,65 @@ class CostEstimate:
source_url: str
def _pricing_date(value: date | datetime | int | float | str) -> date:
if isinstance(value, datetime):
if value.tzinfo is not None:
value = value.astimezone(timezone.utc)
return value.date()
if isinstance(value, date):
return value
if isinstance(value, (int, float)):
return datetime.fromtimestamp(value, timezone.utc).date()
return date.fromisoformat(value[:10])
def _google_flash_rate(*, model_key: str, priced_on: date) -> ModelRate | None:
if model_key == "gemini-3.6-flash" and priced_on < GOOGLE_36_RELEASE_START:
return None
if model_key == "gemini-3.7-flash" and priced_on < GOOGLE_FLASH_INTRO_START:
return None
if model_key not in {"gemini-3.6-flash", "gemini-3.7-flash"}:
return None
model_name = "Gemini 3.7 Flash" if model_key == "gemini-3.7-flash" else "Gemini 3.6 Flash"
if GOOGLE_FLASH_INTRO_START <= priced_on < GOOGLE_FLASH_INTRO_END:
return ModelRate(
0.75,
3.75,
0.075,
f"google-{model_key}-standard-intro@2026-08-13",
(
f"Google {model_name} 프로모션 표준 단가(2026-12-31까지)"
" · 입력 $0.75/M · 캐시 $0.075/M · 출력 $3.75/M"
),
GOOGLE_PRICING_URL,
)
effective_from = "2027-01-01" if priced_on >= GOOGLE_FLASH_INTRO_END else "2026-07-21"
period_label = (
"2027-01-01부터"
if priced_on >= GOOGLE_FLASH_INTRO_END
else "2026-07-21~2026-08-12"
)
return ModelRate(
1.50,
7.50,
0.15,
f"google-{model_key}-standard@{effective_from}",
(
f"Google {model_name} 표준 단가({period_label})"
" · 입력 $1.50/M · 캐시 $0.15/M · 출력 $7.50/M"
),
GOOGLE_PRICING_URL,
)
def _rate(
*,
provider: str,
model: str,
tokens_in: int,
priced_on: date,
) -> ModelRate | None:
provider_key = provider.strip().lower()
model_key = model.strip().lower()
@ -56,15 +114,9 @@ def _rate(
break
if provider_key == "agy_cli":
if model_key == "gemini-3.6-flash":
return ModelRate(
1.50,
7.50,
0.15,
f"google-gemini-3.6-flash-standard@{RATE_CARD_VERSION}",
"Google Gemini 3.6 Flash 표준 단가 · 입력 $1.50/M · 캐시 $0.15/M · 출력 $7.50/M",
GOOGLE_PRICING_URL,
)
flash_rate = _google_flash_rate(model_key=model_key, priced_on=priced_on)
if flash_rate is not None:
return flash_rate
if model_key == "gemini-3.5-flash":
return ModelRate(
1.50,
@ -182,6 +234,7 @@ def estimate_reference_cost(
model: str,
tokens_in: int,
tokens_out: int,
priced_at: date | datetime | int | float | str,
cached_input_tokens: int = 0,
) -> CostEstimate | None:
"""공식 공개 단가로 USD 상당액을 계산한다.
@ -195,7 +248,12 @@ def estimate_reference_cost(
if safe_input == 0 and safe_output == 0:
return None
cached = min(safe_input, max(0, int(cached_input_tokens or 0)))
rate = _rate(provider=provider, model=model, tokens_in=safe_input)
rate = _rate(
provider=provider,
model=model,
tokens_in=safe_input,
priced_on=_pricing_date(priced_at),
)
if rate is None:
return None
uncached = safe_input - cached