feat(admin): Modell-Browser (Cloud) mit Tool-Badge, Preisen & $/Antwort

Phase 1 (Cloud) des Modell-Auswahlmenues:
- Token je Turn im CostMeter (record_openrouter_cost liest prompt/completion_
  tokens) -> globales Turn-Profil (turn_profile, EMA) fuer die $/Antwort-Schaetzung.
- app/model_menu.py: gecachter OpenRouter-Katalog -> Chat-Modelle mit tool_supported
  (supported_parameters), eval_verified (kuratiert), Up/Down-Preisen pro Mio. Token
  und geschaetzter $/Antwort (Profil x Modellpreise).
- GET /api/admin/model-menu; durchsuchbarer Browser im System-Tab, "Verwenden"
  setzt openrouter_llm_model (Freitext/Preset bleiben).
Lokale Modelle (Durchsatz/Strom): Phase 2. Konzept in Ideen/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-30 22:37:36 +02:00
commit a87dc75a46
5 changed files with 233 additions and 3 deletions

View file

@ -175,6 +175,14 @@ async def wipe_all_user_data(request: Request):
return counts
@router.get("/admin/model-menu", dependencies=[Depends(require_admin)])
async def model_menu():
"""Benutzbare Cloud-Modelle (OpenRouter): Tool-Fähigkeit, ⬆/⬇-Preise pro
Mio. Token und geschätzte $/Antwort. Lokale Modelle folgen in Phase 2."""
from app.model_menu import build_model_menu
return await build_model_menu(get_store())
@router.post("/admin/users/{user_id}/token", response_model=UserCreated, dependencies=[Depends(require_admin)])
async def reset_token(user_id: str):
"""Stellt einen neuen Bearer-Token aus; der alte wird sofort ungueltig.