From 7e4505d9b793143f7b960cfbc242a5db3f960720 Mon Sep 17 00:00:00 2001 From: Jeuner <62662523+Jeuners@users.noreply.github.com> Date: Mon, 24 Aug 2026 22:23:07 +0200 Subject: [PATCH] feat: Failover auf lokales Ollama-Modell, wenn OpenRouter fehlschlaegt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenRouter (v.a. :free-Tier) ist nachweislich instabil (502 "temporarily overloaded", Latenz-Ausreisser bis 80s, siehe vorherige Tests). Bisher ist ein Anruf dabei komplett gescheitert und nach telefon/fehler verschwunden. kategorisiere() faengt KategorisierungsFehler von OpenRouter jetzt ab und faellt automatisch auf config.OLLAMA_MODELL zurueck - der Anruf kommt so oder so durch. failover_von landet mit im Live-Log ("⚠ Failover von ..."), damit Ausfaelle sichtbar/auditierbar bleiben. Getestet mit erzwungenem OpenRouter-Fehler (ungueltige Modell-ID, 400) - Failover greift, Ergebnis kommt trotzdem korrekt an. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs --- pipe/categorize.py | 13 ++++++++++++- pipe/process_call.py | 8 ++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pipe/categorize.py b/pipe/categorize.py index 1b3f1e3..b9802bb 100644 --- a/pipe/categorize.py +++ b/pipe/categorize.py @@ -101,11 +101,22 @@ def kategorisiere(transkript: str) -> tuple[dict, dict]: backend, modell = modellwahl.backend_und_modell() start = time.monotonic() if backend == "openrouter": - ergebnis, meta = _mit_openrouter(transkript, modell) + try: + ergebnis, meta = _mit_openrouter(transkript, modell) + except KategorisierungsFehler as fehler: + # OpenRouter (v.a. :free-Tier) ist nachweislich instabil - 502 + # "temporarily overloaded", Latenz-Ausreisser bis 80s. Ein Anruf + # darf daran nicht scheitern und nach telefon/fehler verschwinden + # - Failover aufs lokale Ollama-Modell statt den Anruf zu verlieren. + print(f" ⚠ {backend} fehlgeschlagen ({fehler}) - Failover auf {config.OLLAMA_MODELL}") + ergebnis, meta = _mit_ollama(transkript, config.OLLAMA_MODELL) + meta["failover_von"] = modell + backend, modell = "ollama", config.OLLAMA_MODELL else: ergebnis, meta = _mit_ollama(transkript, modell) meta["backend"] = backend meta["modell"] = modell + meta.setdefault("failover_von", None) meta["dauer_s"] = round(time.monotonic() - start, 2) ergebnis = _notfall_sicherheitsnetz(transkript, _bereinige(ergebnis)) return ergebnis, meta diff --git a/pipe/process_call.py b/pipe/process_call.py index fb056b5..5bf9844 100644 --- a/pipe/process_call.py +++ b/pipe/process_call.py @@ -46,7 +46,8 @@ def verarbeite(audio: str, anrufer_nummer: str | None = None, "aufgelegt.", "stichworte": [], } - meta = {"backend": "-", "modell": "-", "dauer_s": 0.0, "tokens": None, "kosten_usd": None} + meta = {"backend": "-", "modell": "-", "dauer_s": 0.0, "tokens": None, + "kosten_usd": None, "failover_von": None} print(f" Kategorie: {auswertung['kategorie']} · Dringlichkeit: {auswertung['dringlichkeit']}" f" ({meta['modell']}, {meta['dauer_s']}s)") @@ -58,6 +59,8 @@ def verarbeite(audio: str, anrufer_nummer: str | None = None, zusatz += f" · {meta['tokens']} Tok" if meta.get("kosten_usd"): zusatz += f" · ${meta['kosten_usd']:.4f}" + if meta.get("failover_von"): + zusatz += f" · ⚠ Failover von {meta['failover_von']}" protokoll.schreibe( "notfall" if auswertung["dringlichkeit"] == "notfall" else "anruf", f"{auswertung['kategorie']} · {auswertung['dringlichkeit']}" @@ -65,7 +68,8 @@ def verarbeite(audio: str, anrufer_nummer: str | None = None, + f" ({meta['modell']}, {zusatz})", nummer=anrufer_nummer, kategorie=auswertung["kategorie"], dringlichkeit=auswertung["dringlichkeit"], modell=meta["modell"], - dauer_s=meta["dauer_s"], tokens=meta.get("tokens"), kosten_usd=meta.get("kosten_usd")) + dauer_s=meta["dauer_s"], tokens=meta.get("tokens"), kosten_usd=meta.get("kosten_usd"), + failover_von=meta.get("failover_von")) bekannter_kontakt = kontakte.nachschlagen(anrufer_nummer) if bekannter_kontakt: