"""Kosten-/Ersparnis-Berechnung für die Token-Statistik (eine Quelle der Wahrheit). Vergleicht die lokal verbrauchten Tokens gegen die Cloud-Listenpreise vergleichbarer Modellklassen (Stand Juni 2026, USD pro 1M Tokens, in/out) und liefert die so eingesparte Summe. Wird vom System-Router dünn aufgerufen. """ import os # Cloud-Listenpreise je Rolle/Modellklasse: (input_usd_per_1M, output_usd_per_1M). PRICING: dict[str, tuple[float, float]] = { "heavy": (15.0, 75.0), "coder": (3.0, 15.0), "hermes": (1.0, 5.0), "fast": (0.15, 0.60), "scout": (0.15, 0.60), "vision": (0.15, 0.60), "reasoning": (0.15, 0.60), } # Tarif für nicht zuordenbare Tokens (Default-/Fallback-Klasse). DEFAULT_RATE: tuple[float, float] = (0.15, 0.60) # Baseline/Legacy-Tokens (vor modellspezifischem Logging) am Premium-Tarif bewerten, # damit historische Ersparnis erhalten bleibt. BASELINE_RATE: tuple[float, float] = PRICING["heavy"] USD_TO_EUR = float(os.environ.get("MC_USD_TO_EUR", "0.92")) def compute_savings(stats: dict, role_map: dict[str, str | None]) -> dict: """Aggregiert Tokens und berechnet die Cloud-Ersparnis. role_map: Modell-/Alias-Name (lowercase) -> Rolle, zur Tarif-Auflösung. """ prompt = stats.get("prompt_tokens", 0) completion = stats.get("completion_tokens", 0) modeled_p = modeled_c = 0 saved_usd = 0.0 for m_name, m_tokens in (stats.get("models") or {}).items(): mp = m_tokens.get("prompt", 0) mc = m_tokens.get("completion", 0) modeled_p += mp modeled_c += mc role = role_map.get(m_name, m_name) rate_in, rate_out = PRICING.get(role, DEFAULT_RATE) saved_usd += (mp * rate_in + mc * rate_out) / 1_000_000.0 baseline_p = max(0, prompt - modeled_p) baseline_c = max(0, completion - modeled_c) saved_usd += (baseline_p * BASELINE_RATE[0] + baseline_c * BASELINE_RATE[1]) / 1_000_000.0 return { "prompt_tokens": prompt, "completion_tokens": completion, "total_tokens": prompt + completion, "saved_usd": round(saved_usd, 2), "saved_eur": round(saved_usd * USD_TO_EUR, 2), "pricing": {role: {"in": r[0], "out": r[1]} for role, r in PRICING.items()}, }