Dieter Schlüter
7896f608fb
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
...
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
Dieter Schlüter
7b1acd774d
test: manuelles End-to-End-Smoke-Skript gegen OpenRouter (scripts/smoke_e2e.py)
...
- prueft LLM, TTS und STT live (inkl. TTS->STT-Round-Trip); klare [OK]/[FAIL]-Ausgabe
- bewusst ausserhalb von tests/ (pytest sammelt es nicht ein); macht echte Netz-Aufrufe
- Makefile-Target `make smoke`; Doku in README + BEDIENUNGSANLEITUNG
- live ausgefuehrt: LLM/TTS/STT alle bestanden
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 09:49:04 +02:00
Dieter Schlüter
1d338810b1
fix: OpenRouter-STT auf JSON/base64 statt multipart (passend zur OpenRouter-API)
...
Live-Test gegen OpenRouter ergab: /audio/transcriptions erwartet JSON mit
input_audio:{data(base64),format} - NICHT multipart/form-data. Die fruehere
Umstellung auf multipart (OpenAI-Standard) war fuer OpenRouter falsch.
- STT-Provider zurueck auf JSON/base64 (mit robuster Fehlerbehandlung)
- verifiziert per TTS->WAV->STT Round-Trip: Text korrekt zurueck transkribiert
- LLM, TTS und STT funktionieren jetzt alle live gegen OpenRouter
- Doku-Referenz aktualisiert (multipart -> JSON/base64)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 09:31:34 +02:00
Dieter Schlüter
1eb79c1f09
feat: Tageskontingent und Notfall-Eskalation ( #6 )
...
- Quota (app/quota.py): Anfragen pro Nutzer/Tag (usage-Tabelle), DAILY_REQUEST_LIMIT,
pro Nutzer via prefs uebersteuerbar; 429 (REST) bzw. error-Event (WS); Metrik
- Notfall (app/safety/emergency.py): heuristische Erkennung (de/en); Log im Store
(emergency_events) + optionaler Webhook (best-effort) + X-Emergency/emergency-Event;
Metrik emergency_total; Notfaelle umgehen das Kontingent
- verdrahtet in chat/speak/transcribe + WS-Turns
- Tests: 64 gruen (+6); Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur, .env.example)
Hinweis: Notfall-Erkennung ist eine Heuristik (kein Lebensretter); erkannte Texte
sind sensibel -> DSGVO beachten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 05:29:30 +02:00
Dieter Schlüter
6422444017
feat: Resilienz (Fallback-Ketten) und Metriken ( #5 )
...
- Fallback-Provider (app/providers/fallback.py) fuer STT/LLM/TTS: Provider-Kette
der Reihe nach; Config *_FALLBACK; build_orchestrator baut Ketten (dedupliziert)
- LLM-Stream-Fallback nur solange kein Token gesendet wurde
- Metriken (app/metrics.py): In-Memory Counter/Timer, keine externe Dependency
- HTTP-Middleware (Requests/Latenz/Status je Pfad); Pipeline-Stufen-Timing stt/llm/tts;
Fallback-/Fehlerzaehler; GET /api/metrics (JSON + Prometheus)
- Tests: 58 gruen (+6); Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur, .env.example)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 05:19:07 +02:00
Dieter Schlüter
093da817d8
feat: Barge-in/Turn-Manager und VAD-Aeusserungserkennung ( #4 Ausbau)
...
- Barge-in: Antwort-Turn als abbrechbarer asyncio.Task; {"type":"interrupt"} oder
neue Eingabe bricht laufende Antwort ab -> interrupted-Event (/ws/chat + /ws/voice)
- VAD (app/audio/vad.py): energie-basierte Stille-Erkennung (reines Python, int16-PCM)
- /ws/voice opt-in {"type":"start","vad":true}: automatisches Aeusserungsende ohne end
- Tests: 52 gruen (+5: VAD-Unit, Barge-in, VAD-Auto-Segmentierung)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Offen (schwere Deps/Dienste): echte partielle Live-Transkripte (Streaming-STT),
WebRTC (aiortc). STT laeuft heute pro Aeusserung.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 05:06:58 +02:00
Dieter Schlüter
9340d3f998
feat: Audio-Eingang über WebSocket (/ws/voice) - Sprach-zu-Sprach ( #4 Ausbau)
...
- /ws/voice: binaere Audio-Frames puffern, {"type":"end"} -> STT-Transkription
-> transcript-Event -> bestehende Antwort-Pipeline (ack/token/audio/semantic/done)
- ws.py refaktoriert: gemeinsame _resolve + _run_turn fuer /ws/chat und /ws/voice
- stream/audio_stream auch fuer Sprach-Turns nutzbar; mehrere Utterances pro Verbindung
- Tests: 47 gruen (+2: Transkript->Antwort, leerer Puffer)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Hinweis: STT pro Aeusserung (gepuffert); partielle Live-Transkripte (Streaming-STT
mit VAD) bleiben naechster Increment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 04:51:49 +02:00
Dieter Schlüter
b5913b0a44
feat: Audio-Streaming (chunked TTS) über WebSocket ( #4 Ausbau)
...
- SentenceChunker (pipeline/sentence_chunker.py): inkrementelle Satzsegmentierung
- Orchestrator.chat_stream(on_audio): satzweise TTS, Audio-Chunk pro fertigem Satz;
Gesamtaudio zusaetzlich an den Output-Endpunkt
- WS /ws/chat {"audio_stream":true}: audio-Events (json seq + binaerer Frame) live,
kein finales Vollaudio; mit stream kombinierbar
- Tests: 45 gruen (+2: Sentence-Chunker, Audio-Streaming)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 04:43:50 +02:00
Dieter Schlüter
379e002460
feat: Token-Level-LLM-Streaming über WebSocket ( #4 Ausbau)
...
- LLMProvider.stream: Basis-Default (Fallback über complete) + SSE-Streaming
fuer OpenRouter und lokalen OpenAI-kompatiblen Provider; gemeinsamer Parser sse_delta
- Orchestrator.chat_stream: LLM-Token live via on_token-Callback, danach
Spoken-Adapter/Normalizer/TTS/Output; Fallback fuer Provider ohne stream
- WS /ws/chat: opt-in {"stream":true} -> ack -> token* -> semantic -> audio -> done
- Tests: 43 gruen (+5: SSE-Parsing, Default-Fallback, WS-Token-Flow)
- Doku aktualisiert; .gitignore: *.wav (generierte Audio-Ausgaben)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 04:37:37 +02:00
Dieter Schlüter
531b57e08d
feat: Langzeit-Erinnerungen (#3b) und WebSocket-Streaming-Chat ( #4 , erster Increment)
...
#3b Langzeit-Erinnerungen:
- Store: memories-Tabelle + add/get/delete_memory (pro Nutzer)
- API: GET/POST/DELETE /api/me/memories
- chat.py injiziert Nutzer-Erinnerungen als System-Kontext ins LLM (sessionunabhaengig)
- ?debug zeigt memories_len
#4 Echtzeit (erster Increment):
- WS /ws/chat: dauerhafter Kanal, Event-Folge ack -> semantic -> audio (binaer) -> done
- Auth (Token-Query), Session-Gedaechtnis und Erinnerungen wie bei POST /api/chat
- Fehler als error-Event (422/403/502)
- Tests: 38 gruen (Erinnerungs-CRUD/Injektion, WebSocket-Streaming/Auth)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 04:26:55 +02:00
Dieter Schlüter
16a964032e
feat: Konversationsgedaechtnis - Kurzzeit-Gespraechsverlauf pro Session
...
- Store: messages-Tabelle + append_message/get_recent_messages (mit Mandanten-Schutz)
- LLMProvider.complete um history erweitert (openrouter + local bauen system+history+user)
- Orchestrator.chat_text reicht den Verlauf ans LLM weiter
- chat.py: bei session_id letzte HISTORY_MAX_MESSAGES laden, danach User-/Assistant-Turn speichern
- ohne session_id weiterhin zustandslos; ?debug zeigt history_len
- Config HISTORY_MAX_MESSAGES (Default 10)
- Tests: 32 gruen (3 neue Gedaechtnis-Tests)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 04:16:35 +02:00
Dieter Schlüter
e0e69fdf15
feat: Cloud-Fundament - Auth, Persistenz und Mandanten-Trennung
...
- SQLite-Store (app/store.py) hinter Store-Interface: Nutzer + Sessions persistent
- Bearer-Token-Auth (app/auth.py); Nutzerverwaltung via Admin-Key (POST /api/admin/users)
- GET /api/me, PUT /api/me/prefs (dauerhafte Nutzer-Praeferenzen)
- chat/speak/transcribe/sessions auth-geschuetzt; Mandanten-Trennung (fremde Session -> 403)
- Route-Aufloesung: Defaults < Profil < ENV < Nutzer-Prefs < Session < Request
- SessionManager (in-memory) durch Store ersetzt
- AUTH_ENABLED-Schalter (prod an, dev/Tests aus); DB_PATH/ADMIN_API_KEY
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur, deploy-env); data/ gitignored
- Tests: 29 gruen (Auth, Mandanten, Persistenz, Routing)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 02:14:25 +02:00
Dieter Schlüter
293ed257db
Initial commit: Voice Assistant Gateway mit Konfig-/Routing-Fundament
...
- FastAPI-Gateway mit REST-Endpunkten (chat/speak/transcribe/devices/sessions/config)
- Geschichtete Konfiguration mit Profilen (local-dev/hybrid/cloud) via TOML + ENV
- Registry-Pattern + einheitliche Route-Aufloesung (Default->Profil->ENV->Session->Request)
- Device Router (strikt, Singleton) und Output-Lifecycle im Orchestrator
- OpenRouter-Adapter (STT multipart/LLM/TTS) + lokale Provider-Stubs
- Regelbasierte Pipeline (Cleaner/Spoken-Adapter/TTS-Normalizer)
- 22 automatisierte Tests; Doku: README, BEDIENUNGSANLEITUNG, Architektur
- Secrets ausschliesslich ueber Umgebung; .env und lokale config gitignored
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 01:48:56 +02:00