feat(costs): Pro-Nutzer-Kostenerfassung Stufe 1 (OpenRouter-Ist-Kosten)
CostMeter via ContextVars (app/core/costs.py, multitool-ready). Alle
OpenRouter-Calls (LLM, Sonar, Koreferenz, Fallback) senden usage:{include:true}
und buchen die Ist-Kosten je Kategorie (llm/web_search) — inkl. finalem
Streaming-usage-Chunk. cost_usage-Tabelle (user/day/category) + Store-Methoden;
ws.py/chat.py start_meter pro Turn + persist_costs. Statistik: Spalten
"Kosten (Monat)" + "Ø/Anfrage" + Gesamt. Live: 1 Such-Turn ~ $0,0052
(web_search dominiert, LLM ~ $0,00007). Tests: 318.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
21a5250282
commit
d87f0ce424
9 changed files with 171 additions and 10 deletions
|
|
@ -9,6 +9,8 @@ import logging
|
|||
|
||||
import httpx
|
||||
|
||||
from app.core.costs import record_openrouter_cost
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ENDPOINT = "https://openrouter.ai/api/v1/chat/completions"
|
||||
|
|
@ -66,7 +68,7 @@ class Decontextualizer:
|
|||
return text
|
||||
user = (f"Conversation:\n{self._render(history)}\n\n"
|
||||
f"Latest message: {text}\n\nRewritten self-contained message:")
|
||||
payload = {"model": self.model, "temperature": 0.0,
|
||||
payload = {"model": self.model, "temperature": 0.0, "usage": {"include": True},
|
||||
"messages": [{"role": "system", "content": _SYSTEM},
|
||||
{"role": "user", "content": user}]}
|
||||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
|
||||
|
|
@ -74,7 +76,9 @@ class Decontextualizer:
|
|||
async with httpx.AsyncClient(timeout=httpx.Timeout(self.timeout)) as client:
|
||||
resp = await client.post(ENDPOINT, json=payload, headers=headers)
|
||||
resp.raise_for_status()
|
||||
out = (resp.json()["choices"][0]["message"]["content"] or "").strip()
|
||||
data = resp.json()
|
||||
record_openrouter_cost(data.get("usage"), "llm")
|
||||
out = (data["choices"][0]["message"]["content"] or "").strip()
|
||||
except Exception as exc: # noqa: BLE001 — best effort, bei Fehler Original behalten
|
||||
logger.warning("Decontextualizer fehlgeschlagen: %s", exc)
|
||||
return text
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue