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
|
|
@ -11,6 +11,7 @@ from dataclasses import dataclass, field
|
|||
|
||||
import httpx
|
||||
|
||||
from app.core.costs import record_openrouter_cost
|
||||
from app.metrics import metrics
|
||||
from app.providers.llm.base import lang_instruction
|
||||
|
||||
|
|
@ -70,7 +71,8 @@ class SonarTool:
|
|||
logger.warning("SonarTool ohne API-Key")
|
||||
return ToolResult(text=_NO_DATA, ok=False)
|
||||
|
||||
payload = {"model": self.model, "messages": self._messages(query, language)}
|
||||
payload = {"model": self.model, "messages": self._messages(query, language),
|
||||
"usage": {"include": True}}
|
||||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
|
||||
timeout = httpx.Timeout(self.timeout)
|
||||
|
||||
|
|
@ -90,6 +92,7 @@ class SonarTool:
|
|||
return ToolResult(text=_NO_DATA, ok=False)
|
||||
|
||||
data = resp.json()
|
||||
record_openrouter_cost(data.get("usage"), "web_search")
|
||||
try:
|
||||
content = data["choices"][0]["message"]["content"]
|
||||
except (KeyError, IndexError, TypeError):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue