feat(tts): echtes lokales TTS via piper (kein Stub mehr)

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>
This commit is contained in:
Dieter Schlüter 2026-06-17 22:11:20 +02:00
commit cca423dac3
10 changed files with 269 additions and 15 deletions

View file

@ -46,6 +46,15 @@ FASTER_WHISPER_MODEL=base # tiny|base|small|medium|large-v3
FASTER_WHISPER_DEVICE=auto # auto|cpu|cuda
FASTER_WHISPER_COMPUTE_TYPE=default # default|int8|float16|int8_float16
# --- Lokales TTS (piper; Binary + Stimmmodell noetig) ------------------------
# Aktivieren z. B. mit DEFAULT_TTS_PROVIDER=piper (oder --tts-provider piper).
# Stimmen liegen als <name>.onnx (+ .onnx.json) im Voices-Verzeichnis.
# Modelle laden: python -m piper.download_voices de_DE-thorsten-high (o. manuell).
PIPER_BIN=piper # Pfad/Name des piper-Binaries
PIPER_VOICES_DIR=~/.local/share/piper/voices # Verzeichnis der .onnx-Stimmen
PIPER_VOICE=de_DE-thorsten-high # Stimmmodell (ohne .onnx) oder voller Pfad
TTS_SAMPLE_RATE=24000 # Ziel-Sample-Rate (ffmpeg resampelt bei Bedarf)
# --- Resilienz: Fallback-Ketten (kommaseparierte Provider-Namen) ------------
# Faellt der primaere Provider aus, uebernimmt der naechste.
# STT_FALLBACK=faster-whisper