Commit graph

4 commits

Author SHA1 Message Date
Jeuner
7e4505d9b7 feat: Failover auf lokales Ollama-Modell, wenn OpenRouter fehlschlaegt
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs
2026-08-24 22:23:07 +02:00
Jeuner
00176916d7 fix: Notfall-Sicherheitsnetz, Board-Refresh-Bug, Verbindungsverlust-Anzeige
Notfall-Sicherheitsnetz (categorize.py): qwen3:8b stufte "starke
Brustschmerzen ... kriege kaum Luft" reproduzierbar (3/3 Testlaeufe) nur als
"hoch" statt "notfall" ein, obwohl es selbst "Brustschmerzen"+"Atemnot" als
Stichworte erkannte und der Prompt genau diese als Notfall-Beispiele nennt.
Bei Notfall-Erkennung darf man sich nicht allein aufs LLM verlassen -
_notfall_sicherheitsnetz() prueft den rohen Transkripttext deterministisch
gegen die im Prompt selbst genannten Symptome (Atemnot, Brustschmerz,
Bewusstlosigkeit, starke Blutung) und eskaliert nur nach oben, nie runter.

Board-Refresh-Bug (server.py): der Audio-Fix aus einem frueheren Commit
("audio:not([paused])") pruefte ein HTML-Attribut, das <audio> nie gesetzt
hat - der Selektor traf auf JEDES Audio-Element zu, egal ob es lief. Das
Board hat sich seitdem praktisch nie mehr neu gezeichnet, sobald irgendeine
Karte eine Aufnahme hatte (also fast immer) - erklaert "Dashboard
aktualisiert manchmal nicht". Jetzt echte .paused-DOM-Eigenschaft geprueft.

Verbindungsverlust-Anzeige: bisher schluckte hole() Netzwerkfehler still,
das Board blieb unbemerkt eingefroren. Neues Banner ab 2 aufeinanderfolgenden
fehlgeschlagenen Poll-Versuchen (~6s), zeigt Zeitpunkt der letzten
erfolgreichen Aktualisierung, verschwindet automatisch bei Erholung.

Bereits gespeicherter Peter-Fuchs-Fall (Brustschmerz+Atemnot) manuell auf
notfall/notfall nachkorrigiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs
2026-08-24 22:08:38 +02:00
Jeuner
3e2d829542 feat: OpenRouter-Backend + Modell-Dropdown im Leitstand, Live-Log fuer Dauer/Tokens/Kosten
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
2026-08-24 21:43:30 +02:00
Jeuner
1a1280e79d Praxis-Telefon-Agent: Anrufannahme, Transkription, Triage — vollständig on-prem
Nimmt Anrufe einer Hausarztpraxis entgegen, transkribiert sie lokal,
kategorisiert das Anliegen und legt es strukturiert ab. Keine Patientendaten
verlassen den Rechner: Spracherkennung, Sprachmodell und Sprachsynthese laufen
lokal, im Datenpfad steht kein Cloud-Dienst.

Aufbau:
- FreeSWITCH nimmt über einen SIP-Trunk an, spielt die Ansage und nimmt auf.
- pipe.watch erkennt fertige Aufnahmen und schiebt sie durch die Pipe.
- whisper.cpp transkribiert, ein lokales Sprachmodell (Ollama) ordnet in
  Kategorie und Dringlichkeit ein — mit erzwungenem JSON-Schema.
- Ablage lokal, optional Nextcloud (WebDAV) und ein Deck-Board.
- Leitstand (pipe.server): Board mit Eingang/In Bearbeitung/Rückfragen/Erledigt,
  Aufnahmen zum Anhören, Verlauf und Ampeln für alle beteiligten Dienste.

Zugangsdaten und Anrufdaten liegen außerhalb des Repositorys (.env, ablage/,
telefon/). Konfiguration siehe .env.example, Einrichtung siehe README.
2026-08-22 22:37:17 +02:00