Commit graph

16 commits

Author SHA1 Message Date
ea0e3674ad refactor: Notruf-Bridge nutzt seven-send-Library statt eigenem seven.io-Code
Die seven.io-Aufrufe (SMS + Voice/SSML) leben jetzt in der wiederverwendbaren
Library seven-send; die Bridge ist nur noch der HTTP-Adapter und ruft den
synchronen SevenClient via asyncio.to_thread. Eine getestete Stelle für die
API-Logik, ~50 Zeilen Duplikat raus.

- main.py: import SevenClient; _make_client() aus der Env; _dispatch() pro
  Kanal/Nummer; ohne API-Key sauberes "nicht gesetzt"-Ergebnis (kein Versand)
- Tests: mocken jetzt seven_send.client.httpx.post; neuer Test "ohne API-Key
  kein Versand" (6 Tests)
- Doku: Bridge-README + DEPLOYMENT 2.9 — seven-send als venv-Voraussetzung
  (pip install git+https://kitux.de/forgejo/dschlueter/seven_send.git)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 11:50:05 +02:00
7addb903b2 feat: Notruf-Bridge (seven.io) — Webhook-Empfänger für SMS + Anruf
Konkreter Provider hinter dem provider-agnostischen EMERGENCY_WEBHOOK_URL:
ein kleiner FastAPI-Dienst (emergency_bridge/), der das Notruf-Payload der
App entgegennimmt und pro Telefonnummer SMS und/oder TTS-Anruf über die
seven.io-API auslöst.

- main.py: POST /notruf (Bearer-Token-Prüfung), GET /health; seven.io
  SMS (/api/sms) + Voice (/api/voice, Text als SSML, XML-escaped), best
  effort mit Statuscode-100-Auswertung; Kanäle/Texte kommen aus dem Payload
- Betrieb: eigener systemd-Service auf 127.0.0.1:8090, läuft in der
  vorhandenen venv; .env.example + README mit Installations- und
  Verdrahtungsschritten
- Tests: SMS+Anruf-Fan-out, SSML-Escaping, Token-Auth, Kanal-Filter (5 Tests)
- DEPLOYMENT.md: optionaler Abschnitt 2.9 mit Verweis auf die Bridge

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 10:53:34 +02:00
6e824d8f9b feat(2-Schritt3): nginx-Cutover — App per Token-Link, Admin hinter Authelia
Sicherheits-Architektur umgestellt (live verifiziert):
- App-Routen (/, /ws/) ohne Authelia -> Auth via Capability-Token-Cookie
  (Senioren: Ein-Klick-Link, kein 2FA). Remote-User wird in nginx HART
  geleert (Anti-Spoofing: App vertraut Remote-User von der Proxy-IP).
- /api/admin/* (und /api/admin/log) zusätzlich hinter Authelia (Doppelschutz).
- gate_web_ui: statt SSO-Redirect (würde nach Cutover schleifen) eine
  freundliche "Persönlicher Zugang nötig"-Hinweisseite (401).

Endabnahme durch nginx: Link->303+Cookie, /api/me->200 (kein 2FA),
Admin->302 Authelia, Header-Spoofing->401. DEPLOYMENT.md 2.8 aktualisiert.
Test auf neue Hinweisseite angepasst. 219 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 04:45:11 +02:00
f758db218c docs: SMTP-Env ohne Inline-Kommentare + Warnung (Notruf-Mail-Falle)
Der env-Loader nimmt die ganze Zeile als Wert — Inline-Kommentare hinter
SMTP_HOST/PASSWORD/FROM landeten im Wert (DNS-/Auth-/Sender-Fehler). Vorlage
in env.example und DEPLOYMENT.md 2.5 auf reine Werte umgestellt, mit
Warnhinweis und dem Hinweis, dass SMTP_FROM dem SMTP_USER gehören muss.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 03:58:34 +02:00
c35fe6e187 feat(P2): Notruf verschickt E-Mail an Kontaktperson (Testphase)
Beim Notruf-Knopf wird – sofern SMTP konfiguriert ist – eine E-Mail an die
Kontaktperson(en) des Nutzers geschickt (Default: dieter.schlueter@linix.de).
Der Nutzer-Hinweis spiegelt ehrlich wider, ob wirklich etwas rausging:
"Kontaktperson per E-Mail benachrichtigt" vs. "noch keine Benachrichtigung".

- config.py: EMERGENCY_CONTACT_EMAIL + SMTP_* (ohne SMTP_HOST kein Versand);
  veralteten LLM-Klassifikator-Kommentar entfernt.
- emergency.py: SMTP-Versand (best effort, im Thread), lokalisierte Hinweise
  für "gesendet"/"nicht gesendet" (10 Sprachen). Pro-Nutzer-Kontakte via
  prefs.emergency_contacts vorbereitet, Fallback auf Config-Default.
- Test mit gemocktem smtplib. env.example + DEPLOYMENT.md 2.5 dokumentiert.

SMS/Anruf-Eskalation folgt später (eigene Planung). 210 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 03:37:18 +02:00
67a959c4b3 fix(nginx): WebSocket-Upgrade für /api/admin/log (Admin-Log)
Zweite Ursache des toten Log-Tabs: /api/admin/log landete in location /
ohne Upgrade-Header → WS-Handshake scheiterte ("Verbindungsfehler").
Dedizierter location-Block mit Upgrade + Remote-User (Auth via Authelia).
In DEPLOYMENT.md 2.8 dokumentiert; live in nginx eingespielt + verifiziert
(WS streamt echte Journal-Zeilen als Admin 'dschlueter').

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 02:42:43 +02:00
f3f9151894 fix(admin): Phase 0 — Log & Restart reparieren, Status auf Wahrheit
Wurzel-Ursache: Dienst läuft als System-Dienst, Code nutzte aber
systemctl/journalctl --user → Log leer, Restart wirkungslos.

- Log-WS (admin.py): --user → System-journalctl. Erfordert voice in
  Gruppe systemd-journal (siehe DEPLOYMENT.md 2.7.1).
- Restart (admin_llm.py): --user → sudo -n systemctl restart über eng
  begrenzte sudoers-Regel; is-active ebenfalls auf System-Dienst.
- Status (app.js): irrelevante Ollama/llama.cpp-Karte + Backend-Wechsel
  entfernt; zeigt jetzt echtes aktives LLM-Modell (aus Runtime-Config);
  Neustart in eigener "Wartung"-Karte (zieht in Phase 3 nach Konfiguration).
- DEPLOYMENT.md 2.7.1: sudoers-Regel + journal-Gruppe dokumentiert.

Live verifiziert: Log lesbar, Restart ohne Passwort, /health nach 3s zurück.
Tests: 214 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 02:27:18 +02:00
7a0cf0abb4 ci: pre-push-Hook + Installer für lokalen Test-Gate
scripts/git-hooks/pre-push lässt pytest vor jedem Push laufen und bricht
bei roten Tests ab — automatischer Regressionsschutz ohne Forgejo-Runner.
scripts/install-hooks.sh installiert die versionierten Hooks nach .git/hooks
(das selbst nicht versioniert ist). In DEPLOYMENT.md Teil 4.0 dokumentiert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:58:09 +02:00
a6866a6e7f feat: UI-Hinweis bei Cartesia + nicht unterstützter Sprache
Wählt der Nutzer Cartesia und eine feste Sprache, die Cartesia nicht
spricht (AR/IT/RU/PL …), erscheint ein Hinweis, dass automatisch die
lokale Piper-Stimme verwendet wird. Macht den tts_fallback sichtbar,
statt lautlos eine andere Stimme zu liefern.

- /api/config liefert neu available.cartesia_unsupported_languages
  (Single Source of Truth: _UNSUPPORTED_LANGS aus cartesia.py).
- app.js zeigt/aktualisiert den Hinweis bei Sprach-/Provider-Wechsel.
- Test: /api/config listet die nicht unterstützten Sprachen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:49:28 +02:00
304bc02a07 docs: tts_fallback = "piper" in TOML-Config dokumentieren
Der Cartesia→Piper-Fallback (IT/RU/AR/PL) funktioniert nur mit dieser
Einstellung. Da config/voice-assistant.toml gitignored ist, fehlte sie
sonst bei jedem Neu-Deployment und der Fallback wäre still tot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:37:37 +02:00
3c549a05b1 test: Coverage für Gender-/Stimm-System + hermetische Suite
Schließt die Test-Lücken der Gender-/Stimm-Arbeit der letzten Tage:
- test_routing.py: voice_for_route über alle Sprachen × Geschlechter
  (inkl. ES Multi-Speaker #0/#1, "any"→weiblich, Gegengeschlecht-Fallback,
  AR/PT/ZH Einzelstimmen, unbekannte Sprache → None).
- test_piper_tts.py: _parse_speaker (#id) + Gender-Code-Auflösung in
  synthesize() + speaker_id-Durchreichung für Multi-Speaker.
- test_cartesia_tts.py (neu): Voice-Map-Parsing, _resolve_voice_id-Präzedenz,
  nicht unterstützte Sprachen, direkte-UUID-Durchreichung, Cartesia→Piper-Fallback.

Hermetik-Fix in conftest.py: Deployment-Fallback-Ketten (stt/llm/tts_fallback)
werden pro Test auf "" gesetzt. Vorher schlugen 3 WS-Streaming-Tests fehl, weil
llm_fallback="openrouter" aus der TOML durchsickerte und Stub-LLMs ohne stream()
auf den echten OpenRouter durchfielen ("OPENROUTER_API_KEY is empty").

Ergebnis: 213 passed (vorher 164 passed / 3 failed). DEPLOYMENT.md Teil 4.0
dokumentiert den Pflicht-Testlauf vor jedem Deploy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:32:47 +02:00
20c0996a7d docs: Verifikationsdatum aktualisieren (2026-06-24)
Piper alle 10 Sprachen (DE/EN/FR/ES/IT/RU/PL ♂+♀, AR/PT/ZH) und
Cartesia DE/EN/FR/ES/PT/ZH vollständig getestet und verifiziert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 23:27:47 +02:00
74c9147a0f docs: Abschnitt 2.4 auf download_voices.py umstellen
Primärer Installationsweg ist jetzt scripts/download_voices.py statt
manuellem wget-Loop. Manueller Fallback bleibt erhalten. Tabelle auf
16 Stimmen (AR, ZH, PT ergänzt) und Hinweise zu fehlenden Geschlechtern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 23:23:48 +02:00
69990fb871 docs: Piper-Test auf AR, PT und ZH erweitern
Verifikationsabschnitt: Piper-Test deckt jetzt alle 10 Sprachen ab.
AR/PT/ZH haben kein Geschlechtspaar — liefern dieselbe Stimme für ♂+♀
(kareem, faber, huayan). Kommentare im Test machen das explizit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 23:16:59 +02:00
a66236993f docs: Cartesia-Test auf ZH und PT erweitern
Verifikationsabschnitt: Cartesia-Test deckt jetzt alle 6 unterstützten
Sprachpaare ab (DE/EN/FR/ES/PT/ZH je ♂+♀). ZH und PT erfolgreich getestet
(Hua/Kai, Isabella/Bruno).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 23:13:32 +02:00
5351710099 docs: Bedienungsanleitung und Deployment-Guide aktualisieren
- BEDIENUNGSANLEITUNG.md: neue Piper-Stimmen (DE/EN/FR/ES Geschlechtspaare,
  PT/PL/AR), Geschlechtspräferenz (♂/♀-Buttons) dokumentiert, NL durch
  PT/PL/AR ersetzt, Stimmtabelle auf 18 Einträge erweitert
- DEPLOYMENT.md: vollständiger jamulix-Deployment-Guide neu hinzugefügt
  (nginx, Authelia, Piper, Cartesia, Speaker-ID-Unterstützung, alle Änderungen
  gegenüber dem Upstream-Repo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 22:43:59 +02:00