mirror of
https://github.com/Jeuners/Logpy-AgentOne.git
synced 2026-09-09 15:02:33 +02:00
Zweites Kategorisierungs-Backend neben Ollama (pipe/categorize.py), fuer Vergleichstests mit staerkeren Cloud-Modellen. Umschaltbar per Dropdown oben rechts im Leitstand (pipe/modellwahl.py, geteilte telefon/modell.json) - der laufende Watcher braucht dafuer keinen Neustart, die Auswahl wird bei jedem Anruf frisch gelesen. Jede Kategorisierung loggt jetzt Backend/Modell/Dauer/Tokens/Kosten mit ins Leitstand-Verlauf (protokoll.schreibe), nicht nur versteckt in meta.json. Testergebnis (Nemotron ueber OpenRouter, :free-Tier): stark schwankende Latenz (8,5s bis 80s je nach Modell/Auslastung), einmal 502 "temporarily overloaded" - :free-Modelle sind fuer spaeter geplanten Echtzeit-Dialog ungeeignet, dafuer braucht es ein bezahltes/dediziertes Tier. telefon/modell.json ist Laufzeit-Zustand, kein Quellcode - neu ignoriert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs
63 lines
2.5 KiB
Python
63 lines
2.5 KiB
Python
"""Aktives Kategorisierungs-Modell - umschaltbar aus dem Leitstand (Dropdown
|
|
oben rechts), ohne .env-Aenderung oder Neustart des Watchers.
|
|
|
|
Der Watcher (pipe.watch, Langzeit-Prozess) und der Leitstand (pipe.server,
|
|
eigener Prozess) laufen getrennt - die Auswahl wird deshalb in einer kleinen
|
|
JSON-Datei geteilt, die categorize.py bei jedem Anruf frisch liest (kein
|
|
Caching), damit eine Umschaltung sofort beim naechsten Anruf greift.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
from . import config
|
|
|
|
DATEI = config.TELEFON / "modell.json"
|
|
|
|
# Feste, kuratierte Auswahl statt freier Eingabe - ein Tippfehler in einer
|
|
# Modell-ID im Leitstand darf nicht den naechsten Anruf scheitern lassen.
|
|
# "openrouter"-Eintraege sind zum Testen gedacht (Transkript verlaesst dabei
|
|
# den Rechner) - nicht fuer den Praxisbetrieb.
|
|
AUSWAHL = [
|
|
{"id": "ollama", "label": f"{config.OLLAMA_MODELL} (lokal)",
|
|
"backend": "ollama", "modell": config.OLLAMA_MODELL},
|
|
{"id": "or-ultra", "label": "Nemotron Ultra 550B (OpenRouter, Test)",
|
|
"backend": "openrouter", "modell": "nvidia/nemotron-3-ultra-550b-a55b:free"},
|
|
{"id": "or-lightning", "label": "Nemotron 3.5 Lightning (OpenRouter, Test)",
|
|
"backend": "openrouter", "modell": "nvidia/nemotron-3.5-lightning:free"},
|
|
]
|
|
# Optionaler vierter Eintrag zum schnellen Ausprobieren eines beliebigen
|
|
# OpenRouter-Modells, ohne Code zu aendern - einfach OPENROUTER_MODELL in
|
|
# .env setzen.
|
|
if config.OPENROUTER_MODELL:
|
|
AUSWAHL.append({"id": "or-custom", "label": f"{config.OPENROUTER_MODELL} (OpenRouter, Test)",
|
|
"backend": "openrouter", "modell": config.OPENROUTER_MODELL})
|
|
_STANDARD = AUSWAHL[0]["id"]
|
|
_NACH_ID = {e["id"]: e for e in AUSWAHL}
|
|
|
|
|
|
def aktuelle_id() -> str:
|
|
"""Liest die aktive Auswahl. Unbekanntes/Fehlendes gilt als Standard."""
|
|
try:
|
|
wert = json.loads(DATEI.read_text(encoding="utf-8")).get("id")
|
|
except Exception:
|
|
return _STANDARD
|
|
return wert if wert in _NACH_ID else _STANDARD
|
|
|
|
|
|
def setze(kennung: str) -> bool:
|
|
"""Schreibt die Auswahl. False, wenn die ID nicht vorgesehen ist."""
|
|
if kennung not in _NACH_ID:
|
|
return False
|
|
try:
|
|
DATEI.parent.mkdir(parents=True, exist_ok=True)
|
|
DATEI.write_text(json.dumps({"id": kennung}), encoding="utf-8")
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def backend_und_modell() -> tuple[str, str]:
|
|
"""Backend + Modell-ID der aktiven Auswahl, fuer categorize.py."""
|
|
eintrag = _NACH_ID[aktuelle_id()]
|
|
return eintrag["backend"], eintrag["modell"]
|