pocket-tts-german-wyoming

pocket-tts-german-wyoming

Docker app from Marco T's pocket-tts' Repository

Overview

Native Rust German Pocket TTS server with Wyoming protocol support for Home Assistant. CPU-only streaming TTS: German/de-DE, 24 kHz mono PCM16 LE, Q8 by default, 27 official German voice states and configurable speech speed. Models and voices are downloaded from pinned official sources when missing and persist across restarts. Compatible local assets can be installed manually. No Python, PyTorch or GPU runtime. Add Wyoming Protocol manually in Home Assistant using the host address and Wyoming port. This template prepares a future registry release; no public image or CA listing is currently claimed.

pocket-tts-german-wyoming

pocket-tts-german-wyoming

Natives deutsches Pocket TTS in Rust als Wyoming-TTS-Dienst für Home Assistant. CPU-only, getestet auf Intel N100 (linux/amd64, Gracemont/AVX2). Die Docker-Runtime enthält weder Python, PyTorch, GPU-Bibliotheken, Cargo noch einen Compiler.

  • Fest gepinntes offizielles deutsches Modell, standardmäßig Q8; FP32 bleibt verfügbar.
  • Echtes inkrementelles FlowLM → zustandsbehaftetes Mimi → PCM → Wyoming-Streaming.
  • 24.000 Hz, Mono, vorzeichenbehaftetes PCM16 Little Endian; kein Resampling der Ausgabe.
  • 27 validierte offizielle Voice-States, ausschließlich mit Locale de-DE angeboten.
  • Juergen als Standardstimme; Stimmenwahl über Wyoming; unbekannte Stimmen führen zu einem eindeutigen Fehler.
  • Native deutsche SPAN-/Prioritäts-Textnormalisierung und Streaming-Sprachgeschwindigkeitssteuerung.
  • Persistente Modell-/Stimmenspeicherung, atomare validierte Downloads, separate Q8-Derivate.
  • Nativer Readiness-Healthcheck, sauberes Herunterfahren, jeweils eine Synthese gleichzeitig.

Das reguläre Multi-Stage-Image und der Home-Assistant-Hörtest wurden auf dem N100 erfolgreich bestanden. Dieses Repository stellt ein lokal baubares Docker-Projekt bereit; es wird hier nicht behauptet, dass bereits ein Registry-Image oder ein Eintrag in Unraid Community Applications veröffentlicht ist.

Build und Docker

docker build --platform linux/amd64 -t pocket-tts-german-wyoming:local .

Der Build verwendet fest Rust 1.99.0 und gepinnte Cargo-Abhängigkeiten. Die Debian-Build-Pakete verwenden Bookworm-Repositories und keinen eingefrorenen Paket-Snapshot. Die Runtime ist scratch mit den tatsächlich benötigten ELF-Bibliotheken, CA-Zertifikaten und Lizenzinformationen. Das feste Gracemont-Target erfordert eine kompatible AVX2-CPU; dies ist kein generisches Image für ältere x86-CPUs oder ARM.

Erstelle eigene beschreibbare Modell- und Stimmenverzeichnisse, die dem Container-Benutzer gehören (standardmäßig UID 99 / GID 100). Ändere keine Berechtigungen anderer Projekte.

docker run -d --name pocket-tts \
  --restart unless-stopped --read-only --cap-drop ALL \
  --security-opt no-new-privileges \
  -p 10204:10204 \
  -v /absolute/path/to/dedicated/models:/app/models \
  -v /absolute/path/to/dedicated/voices:/app/voices \
  -e POCKET_TTS_SPEED=1.0 \
  pocket-tts-german-wyoming:local

Der Health-Status wird erst dann „ready“, wenn Modell und Standardstimme verfügbar sind und Wyoming antwortet. Beim ersten Start können Assets heruntergeladen und Q8-Dateien erzeugt werden; bei späteren Starts werden sie validiert und wiederverwendet. Das Originalmodell wird niemals überschrieben. Siehe docker/README.md und docker/compose.yaml. Das vorbereitete Unraid-Template befindet sich unter templates/pocket-tts-german-wyoming.xml, das öffentliche Icon unter icons/pocket-tts.png. Der vorgesehene Image-Pfad ghcr.io/marco-taylor/pocket-tts-german-wyoming:latest und die GitHub-Raw-URLs sind nur vorbereitet; Image und CA-Eintrag sind noch nicht veröffentlicht. Das Template mappt Wyoming TCP 10204 sowie eigene models-/voices-Verzeichnisse unter /mnt/user/appdata/pocket-tts-german-wyoming/ auf /app/models und /app/voices. Stelle sicher, dass diese Verzeichnisse für UID 99 / GID 100 beschreibbar sind. Die Sprachgeschwindigkeit ist von 0.8 bis 1.2 konfigurierbar, Standard ist 1.0; Zwischenwerte sind zulässig.

Füge in Home Assistant manuell Wyoming Protocol hinzu und verwende den Docker-Host sowie den veröffentlichten Port (standardmäßig 10204). Wähle pocket-tts, Deutsch (Deutschland) und eine Stimme. Eine mDNS-Ankündigung ist nicht implementiert. Home Assistant selbst wird von diesem Projekt nicht konfiguriert.

Konfiguration

./.env.example dokumentiert die Einstellungen; das Binary lädt diese Datei nicht automatisch. Übergib die ENV-Variablen an Docker, Compose oder deinen Prozess.

Variable Standard Bedeutung
POCKET_TTS_LANGUAGE german Diese Version unterstützt die gepinnte deutsche Architektur
POCKET_TTS_MODEL_PATH nicht gesetzt Explizites lokales Modellverzeichnis; deaktiviert automatisches Ersetzen/Herunterladen
POCKET_TTS_MODELS_DIR /app/models Persistentes Modell-Stammverzeichnis
POCKET_TTS_VOICES_DIR /app/voices Persistentes Stammverzeichnis für offizielle/lokale Stimmen
POCKET_TTS_VOICE juergen Konfigurierbare Standardstimme
POCKET_TTS_QUANTIZE true Q8; false wählt FP32
POCKET_TTS_THREADS 2 Backend-Threads, zulässig 1–4; auf N100 getestet
POCKET_TTS_NORMALIZE true Deutsche Normalisierung vor dem Pocket-Tokenizer
POCKET_TTS_SPEED 1.0 Sprachgeschwindigkeit, kontinuierlicher Bereich 0.8–1.2
POCKET_TTS_VOICE_CACHE_MB 32 Lazy-LRU-Stimmencache, zulässig 16–512 MiB
POCKET_TTS_DOWNLOAD_VOICES true Verwaltet die gepinnten öffentlichen offiziellen Stimmen automatisch
WYOMING_HOST 0.0.0.0 Listen-Interface
WYOMING_PORT 10204 TCP-Port des Containers/Prozesses
RUST_LOG info error, warn, info, debug oder trace

Erweiterte bestehende Optionen: POCKET_TTS_NORMALIZER=safe ist das getestete Release-Profil. span, misaki und final sind historische Vergleichsprofile und werden für den normalen Betrieb nicht empfohlen; ihre weiter gefassten experimentellen Regeln sind unter safe nicht aktiv. POCKET_TTS_READY_FILE schreibt optional einen diagnostischen Readiness-Snapshot; das übergeordnete Verzeichnis muss existieren und beschreibbar sein.

Sprachgeschwindigkeit

Wert Bedeutung
0.8 Langsamer
1.0 Normal / Referenz
1.2 Schneller

Zwischenwerte wie 0.85 und 1.05 sind zulässig. Nicht gesetzt bedeutet 1.0. Nicht endliche, fehlerhaft formatierte, leere oder außerhalb des Bereichs liegende Werte verursachen einen Start-/Konfigurationsfehler: kein Clamping und kein stiller Fallback.

Native begrenzte Streaming-WSOLA-Verarbeitung folgt auf Mimi, wenn die Geschwindigkeit von 1.0 abweicht. Die Ausgabe bleibt 24 kHz Mono PCM16 LE; die Samplerate wird nicht uminterpretiert und es wird nicht auf eine vollständige Wellenform gewartet. Die lokale Wellenformausrichtung erhält die Tonhöhe weitgehend, wobei Time-Stretch-Artefakte auftreten können. Bei 1.0 wird das ursprüngliche PCM unverändert durchgereicht; die getestete Referenz war byte-identisch. ENV wird beim Start gelesen: Eine Änderung der Geschwindigkeit erfordert das Neuerstellen des Docker-Containers mit der neuen ENV und nicht lediglich einen Neustart.

Deutsche Normalisierung

Die vorhandenen Regeln decken Zahlen, negative Werte, Dezimalzahlen mit Komma, deutsche Tausendertrennung, kalendergeprüfte numerische und ausgeschriebene Monatsdaten mit kontextabhängigen Ordinalformen, Uhrzeiten, Temperaturen, Prozentangaben und gängige Home-Assistant-Einheiten ab. Strukturierte Spans werden genau einmal verarbeitet; geschützte technische Tokens haben Vorrang. Der Standard enthält neun eng begrenzte und getestete, von Misaki inspirierte Ergänzungen: Euro, Cent, z. B., ca. vor Zahlen, bzw., inkl., kontextabhängiges Nr., etc. und Monatsabkürzungen. Die Genauigkeit von Euro-/Cent-Beträgen bleibt erhalten. Erweiterungen für Dr., Prof., Fr. und AG bleiben im Standardprofil ausgeschlossen. Dies ist unser Rust-Normalizer, nicht Misaki G2P, espeak-ng oder ein Python-Dienst.

RAW-, normalisierte und Tokenizer-Strings werden derzeit zu Diagnosezwecken auf INFO geloggt. Verwende RUST_LOG=warn, wenn diese potenziell privaten Texte nicht protokolliert werden sollen. Die Erkennung frei formulierter Entitätsnamen und mehrdeutiger technischer Strings ist konservativ, kann jedoch nicht jedes unbekannte Format schützen. Die Modellaussprache ist für beliebige Texte nicht garantiert.

Modelle und Stimmen

Quellen, Revisionen, Größen und SHA256 sind in ./assets.lock.json und assets/german-voices.lock.json fest gepinnt. Öffentliche offizielle States benötigen kein HF_TOKEN. Im Git-Repository/Image sind keine Assets enthalten. Downloads verwenden eigene temporäre Dateien, Validierung und atomare Umbenennung ohne Überschreiben; Manifeste werden zuletzt geschrieben. Vorhandene ungültige Dateien werden gemeldet und niemals stillschweigend ersetzt. Unterbrochene Teildateien werden erkannt und zur Prüfung beibehalten.

Ein explizites lokales Modellverzeichnis benötigt kompatible config.yaml, tokenizer.json und model.safetensors; inkompatible oder unvollständige Daten führen ohne automatischen Fallback zu einem Fehler. Separate Q8-Dateien benötigen ebenfalls ihre Provenienz-/Hash-Sidecar-Datei. Q8 quantisiert die unterstützten FlowLM-Projektions-/FFN-Tensoren; Mimi und KV bleiben FP32.

Offizielle States liegen unter /app/voices/official/german/<revision>/. Lokale States werden beim Start rekursiv erkannt, zum Beispiel /app/voices/local/my_voice.safetensors, und als local/my_voice angeboten. Sie benötigen kompatible eingebettete Metadaten oder eine benachbarte my_voice.voice.json:

{
  "model_sha256": "<original model SHA256>",
  "model_revision": "<pinned model revision>",
  "language": "german",
  "state_format": "pocket-tts-kv-v1",
  "quantization": "fp32-kv"
}

KV-Formen, Offsets, Padding und endliche Werte werden validiert. Inkompatible Stimmen werden mit Warnungen übersprungen. Eine fehlende gültige Standardstimme hält Readiness auf false. Nur die Standardstimme wird vorgewärmt/gepinnt; andere verwenden einen begrenzten Lazy-LRU-Cache. Dessen Budget ist kein RAM-Limit für den gesamten Prozess. WAV-Voice-Cloning ist nicht implementiert.

Entwicklung und Tests

Rust 1.99.0, ein x86_64-Linux-C-Linker und eine Gracemont-kompatible CPU werden benötigt.

cargo fmt --all --check
cargo test --locked --workspace
cargo build --locked --release -p pocket-tts-wyoming

Unit-/Regressionstests benötigen keine heruntergeladenen Gewichte. Explizit ignorierte Hardware-/TCP-Tests benötigen kompatible lokale Assets und sollten nur in einer eigenen isolierten Umgebung ausgeführt werden. Erzeugte WAVs/Logs gehören unter ignorierte artifacts. Output-Streaming unterscheidet sich von Input-Text-Streaming: Wyoming supports_synthesize_streaming=false bezeichnet nicht unterstützte Streaming-Texteingabe. Verbindungsabbrüche brechen die Synthese ab; gleichzeitige Anfragen erhalten busy.

Danksagungen und Lizenz / Drittanbieter-Lizenzen

Vielen Dank an die Mitwirkenden von Kyutai Pocket TTS, gradium-ai XN / xn-ptts und Misaki. Misaki diente als Analyse-/Referenzquelle für ausgewählte Normalisierungsregeln, nicht als Runtime oder Phonemizer. Historisch angepasster Vergleichsquellcode behält seine Apache-2.0-Lizenz.

Unser eigener Code: MIT, Copyright (c) 2026 Marco Taylor, ./LICENSE. Drittanbieter-Code und Assets behalten ihre jeweiligen Lizenzen; siehe ./THIRD_PARTY_NOTICES.md. Insbesondere deklariert das gepinnte Kyutai-Modell-/Stimmen-Repository CC BY 4.0: Modelle/Stimmen werden nicht unter unserer MIT-Lizenz neu lizenziert. Lokale benutzerdefinierte Assets können andere Lizenzen besitzen. Vendored xn-ptts bleibt MIT OR Apache-2.0; von Misaki adaptierte Dateien bleiben Apache-2.0.

Requirements

linux/amd64 with Gracemont-compatible AVX2 CPU; tested on Intel N100. Dedicated models and voices directories must be writable by UID 99 / GID 100. First initialization needs Internet access unless compatible local assets are installed. No Web UI.

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/marco-taylor/pocket-tts-german-wyoming:latest
Last Updated2026-10-08
First Seen2026-10-08

Runtime arguments

Network
bridge
Privileged
false
Extra Params
--restart unless-stopped --read-only --cap-drop ALL --security-opt no-new-privileges

Template configuration

Wyoming PortPorttcp

Wyoming TCP port for Home Assistant. Container port remains 10204.

Target
10204
Default
10204
Value
10204
ModelsPathrw

Dedicated persistent models directory. Must be writable by UID 99 / GID 100; existing user files are not overwritten.

Target
/app/models
Default
/mnt/user/appdata/pocket-tts-german-wyoming/models
Value
/mnt/user/appdata/pocket-tts-german-wyoming/models
VoicesPathrw

Dedicated persistent voices directory. Must be writable by UID 99 / GID 100; existing user files are not overwritten.

Target
/app/voices
Default
/mnt/user/appdata/pocket-tts-german-wyoming/voices
Value
/mnt/user/appdata/pocket-tts-german-wyoming/voices
Model languageVariable

Only german is supported; Wyoming advertises de-DE.

Target
POCKET_TTS_LANGUAGE
Default
german
Value
german
Local model pathVariable

Optional compatible model path inside the container. When set, no automatic model download or replacement occurs.

Target
POCKET_TTS_MODEL_PATH
Models directoryVariable

Persistent model root. Keep aligned with the models volume target.

Target
POCKET_TTS_MODELS_DIR
Default
/app/models
Value
/app/models
Voices directoryVariable

Persistent official and local voice root. Keep aligned with the voices volume target.

Target
POCKET_TTS_VOICES_DIR
Default
/app/voices
Value
/app/voices
Default voiceVariable

Default voice name. 27 pinned official German voices plus compatible local states are discovered at startup. See README and assets/german-voices.lock.json.

Target
POCKET_TTS_VOICE
Default
juergen
Value
juergen
Q8 quantizationVariable

true uses Q8; false uses FP32. Q8 derivatives are stored separately; the original model is never overwritten.

Target
POCKET_TTS_QUANTIZE
Default
true
Value
true
CPU threadsVariable

Backend threads: 1 to 4. Intel N100 tested with 2.

Target
POCKET_TTS_THREADS
Default
2
Value
2
German normalizationVariable

Native German SPAN/Priority normalization before the Pocket TTS tokenizer.

Target
POCKET_TTS_NORMALIZE
Default
true
Value
true
Speech SpeedVariable

Speech speed / Sprechgeschwindigkeit. Valid range: 0.8–1.2; default: 1.0. Intermediate values allowed. Invalid values cause a startup error; no clamping.

Target
POCKET_TTS_SPEED
Default
1.0
Value
1.0
Wyoming listen portVariable

Container listen port. Keep 10204 to match the port mapping; change only the host port when necessary.

Target
WYOMING_PORT
Default
10204
Value
10204
Log levelVariable

error, warn, info, debug or trace. INFO currently logs input, normalized and tokenizer text; use warn for privacy.

Target
RUST_LOG
Default
info
Value
info
Voice cache MiBVariable

Lazy voice LRU budget: 16–512 MiB. Not a total-process RAM limit.

Target
POCKET_TTS_VOICE_CACHE_MB
Default
32
Value
32
Download official voicesVariable

Automatically download missing pinned public official voice states. Existing valid states are reused; local states are not overwritten.

Target
POCKET_TTS_DOWNLOAD_VOICES
Default
true
Value
true