Menue zeigt nur tatsaechlich nutzbare Vorlese-Optionen, um Verwirrung durch
folgenlose Eintraege zu vermeiden:
- Backend ist alleinige Quelle: /api/config liefert fertiges tts_menu
(Chatterbox nur wenn erreichbar, Cloud nur mit OpenRouter-TTS, Cartesia nur
mit Key). piper bleibt garantierter, immer sichtbarer Default.
- Frontend blendet aus statt auszugrauen; 'Im Geraet' nur auf Mobilgeraeten
(isMobile). Aktive/gespeicherte Auswahl auf einen sichtbaren Provider
geklemmt -> kein Server-422.
- 4x refresh*Preset + 3x /api/config-Fetch -> 1x refreshTtsMenu; /api/config
serverseitig 30s gecacht (spart die bisher kostenpflichtige OpenRouter-Probe
pro Seitenladen).
GPU-Erkennung zentralisiert (keine Dopplung):
- app/capabilities.py: detect_physical_gpus/resolve_gpus (nvidia-smi).
- Neues Setting GPUS (auto|none|0,1,2), beim Start an CUDA_VISIBLE_DEVICES
gekoppelt -> angezeigt = real nutzbar. admin_llm nutzt dieselbe Erkennung.
Tests: tests/test_capabilities.py (Maske, Kopplung, Menue-Sichtbarkeit, GPUs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Loest #7. Der chatterbox-Stub wird durch eine echte Anbindung an den lokalen
Chatterbox-HTTP-Dienst ersetzt (POST /speak -> /status pollen -> GET /audio, WAV).
no_playback=true -> der Dienst spielt nicht lokal ab, liefert nur Bytes. WAV->PCM
(24 kHz, Resampling bei Bedarf). Waehlbar via tts_provider=chatterbox; piper bleibt
der schnelle Default (chatterbox ist ~echtzeit-langsam, dafuer klonbare Stimme).
- config: CHATTERBOX_BASE_URL/_VOICE/_LANG/_SPEED/_TIMEOUT; Registry verdrahtet
- Tests: gemockter httpx (Synthese, WAV/Resample, Job-Fehler, Stimmenwahl)
- Doku: README, Architektur (#7), deploy/README (GPU-Pinning per UUID, no_playback)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Discovery zeigte: YunoHost reicht den Usernamen nicht als Header durch, sondern im
signierten Cookie "yunohost.portal" (JWT, Claim "user"). Die Forward-Auth liest jetzt
die Identitaet aus Header ODER Cookie - nur von der Proxy-Quell-IP akzeptiert.
HS256-Signaturpruefung optional via TRUSTED_AUTH_JWT_SECRET (stdlib hmac, kein Dep).
- config: trusted_auth_cookie / _cookie_claim / _jwt_secret
- nginx-Vorlage + deploy/README: keine Identitaets-Header-Zeile mehr noetig; SSO-Schutz
der Subdomain ist Pflicht (sonst Spoofing)
- Tests: Cookie-Extraktion, Signaturpruefung, Proxy-IP-Trust
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- app/core/memory_extractor.py: LLM destilliert nach je N Turns dauerhafte
Fakten/Vorlieben aus dem Verlauf, dedupliziert gegen vorhandene Erinnerungen
und legt sie ab - best-effort, nicht-blockierend (Hintergrund-Task), eigener
Extraktions-Prompt (JSON, Reasoning aus), Cap-Begrenzung
- Trigger in /api/chat und /ws/voice nach dem Persistieren des Turns
- Konfig: MEMORY_EXTRACTION_ENABLED/_EVERY_N_TURNS/_MAX/_PROVIDER
- Tests: Extraktion, Dedup, kaputtes JSON, Cap, leeres Gespraech, Scheduling
- Doku: README + Architektur-Roadmap (Punkt 3 erledigt)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BEDIENUNGSANLEITUNG (B1): neuer Abschnitt 'Stimme des Cloud-TTS (OpenRouter) waehlen'
-- Gateway pflegt keine eigene Liste, reicht OPENROUTER_TTS_VOICE durch; Stimmen
haengen vom Modell ab (Gemini-Familie ~30 Stimmen, OpenAI gpt-4o-mini-tts), Umstellen
global (.env) und pro Aufruf (voice-Feld in /api/speak,/api/chat), Hinweis auf
fehlende --voice-Option in voice_loop. .env.example: Verweis bei OPENROUTER_TTS_VOICE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BEDIENUNGSANLEITUNG: Tabelle der aktuell installierten Stimmen (DE/EN/ES/FR,
Qualitaet, Default thorsten-high), Hinweis auf fehlende weibliche DE-high-Stimme
und dass chatterbox noch Stub ist. .env.example: nicht funktionierenden
'python -m piper.download_voices'-Befehl durch ls + huggingface-Hinweis ersetzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PiperTTSProvider ruft das piper-Binary (--output-raw) async auf, liest die native
Sample-Rate aus der .onnx.json und resampelt per ffmpeg auf 24000 Hz (Gateway-Norm).
Nicht passende Stimmen (z. B. Cloud-Stimme 'Zephyr' aus der Route) fallen auf die
konfigurierte Default-Stimme zurueck. Damit ist eine voll-lokale Konstellation
(faster-whisper + Ollama + piper) moeglich -> keine API-Kosten, max. Datenschutz.
- config: PIPER_BIN/PIPER_VOICES_DIR/PIPER_VOICE/TTS_SAMPLE_RATE (+ .env.example)
- dependencies: piper-Factory mit Settings verdrahtet
- tests: tests/test_piper_tts.py (offline, Fake-Binary; Resample-Test skippt ohne ffmpeg);
e2e/auth-Tests nutzen jetzt einen Stub-TTS statt 'piper' als Pseudo-Stub
- docs: README, BEDIENUNGSANLEITUNG (voll-lokal-Beispiel), Architektur-Roadmap
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>