From ff064685cec04ba59ea97663a4014681b9c03c04 Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:09:29 +0200 Subject: [PATCH] router: TTS auf offiziellen Kikiri-Deutsche-Pfad umgestellt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ersetzt die alte Implementierung (kokoro 0.7.16 + espeak.EspeakG2P) durch den offiziellen Kikiri-Deutsche-Inferenzpfad: - semidark/kokoro-Fork (0.9.4) mit lang_code='d' - semidark/misaki-Fork (0.9.4) mit misaki.de.DEG2P (Text-Normalisierung + espeak-ng + Aussprache-Overrides) - Verbessertes Chunking (Split an Satzgrenzen, 400 Zeichen) - repo_id='hexgrad/Kokoro-82M' für KModel/KPipeline Änderungen: - router/tts_worker.py: KModel/KPipeline API aktualisiert, Monkey-Patching entfernt, Docstring aktualisiert - deploy/install.sh: semidark-Forks installieren (misaki[de], kokoro --no-deps, spacy für misaki.en-Import) - README.md: G2P-Pfad, Chunking, Python-Pakete, Python-3.13-Hinweis Getestet: 43/43 lokale Tests, E2E auf Zielsystem (WAV/MP3, LAN-Zugriff, parallele Qwen/TTS-Operation, Chat intakt). --- README.md | 37 ++++++++++++++++++++++--------------- deploy/install.sh | 19 ++++++++++++------- router/tts_worker.py | 23 +++++++++++++++++------ 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 7b1fb56..5a74391 100644 --- a/README.md +++ b/README.md @@ -181,8 +181,12 @@ Qwen/llama.cpp noch FLUX/GPU – er teilt sich nur den Prozessor. - **Modell:** Kokoro-82M (hexgrad) mit zwei deutschen Feintunings (`kikiri-tts/kikiri-german-martin`, `kikiri-tts/kikiri-german-victoria`, beide Apache 2.0, je ~327 MB). -- **G2P:** deutsche Phonemisierung über `espeak-ng` (phonemizer), kein spacy - nötig. Deutsche Sprachunterstützung per Patch (kokoro PR #340). +- **G2P:** Offizieller Kikiri-Deutsche-Pfad via `misaki.de.DEG2P` + (semidark/misaki-Fork 0.9.4): Text-Normalisierung (Zahlen, Daten, + Uhrzeiten, Währung, Abkürzungen) + `espeak-ng`-Phonemisierung + + Aussprache-Overrides für Marken-/Tech-Begriffe. Kein spacy nötig. +- **Pipeline:** semidark/kokoro-Fork (0.9.4) mit `lang_code='d'` und + verbessertem Chunking (Split an Satzgrenzen, 400 Zeichen). - **Venv:** eigenes Venv unter `/opt/mike-ai/kokoro/venv/` mit CPU-only `torch` (keine CUDA-Abhängigkeit, kein Konflikt mit dem Bild-Venv). - **Modelle:** `/opt/mike-ai/models/kokoro/` (persistent). @@ -218,10 +222,11 @@ curl -s http://192.168.1.196:8081/v1/audio/speech \ -d '{"input":"Guten Tag.","voice":"victoria","speed":1.5,"response_format":"wav"}' -o out.wav ``` -**Lange Texte:** Das Modell verarbeitet pro Segment max. 510 Phoneme -(~25–30 s). Längere Texte werden mit Zeilenumbrüchen (`\n`) in Segmente -teilt; jedes Segment wird einzeln synthetisiert und die Audios -zusammengeführt. +**Lange Texte:** Die Pipeline splittet automatisch an Satzgrenzen +(400 Zeichen pro Chunk). Längere Texte werden in Segmente geteilt; +jedes Segment wird einzeln synthetisiert und die Audios zusammengeführt. +Zeilenumbrüche (`\n`) im Text werden als zusätzliche Segmentgrenzen +behandelt. ### Verhalten @@ -258,20 +263,22 @@ RAM-Belegung des Workers: ~3.5 GB (inkl. torch, beide Modelle). ### Erforderliche Python-Pakete (im Kokoro-Venv) - `torch` (CPU-only, `--index-url https://download.pytorch.org/whl/cpu`) -- `kokoro` (0.7.16, mit `--no-deps` installiert) -- `misaki` (G2P, ohne `[en]`-Extra → kein thinc 9.x / spacy) -- `phonemizer` + System-Paket `espeak-ng` (deutsche G2P) +- `kokoro` (0.9.4, semidark-Fork, mit `--no-deps` installiert) +- `misaki` (0.9.4, semidark-Fork, mit `[de]`-Extra → `phonemizer-fork` + + `espeakng-loader`, kein spacy-curated-transformers) +- `spacy` (nur für `misaki.en`-Import, nicht für deutschen Pfad) +- `num2words` (für `misaki.en`-Import) - `soundfile`, `lameenc` (Audio-Formate wav/mp3/flac/pcm) -- `huggingface-hub`, `loguru`, `scipy`, `transformers`, `regex`, `num2words` +- `huggingface-hub`, `loguru`, `transformers`, `regex` Das Venv liegt unter `/opt/mike-ai/kokoro/venv/` und wird von `install.sh` automatisch angelegt (nur wenn noch nicht vorhanden). -**Hinweis (Python 3.13):** `kokoro` verlangt offiziell `misaki[en]`, das -`spacy-curated-transformers` → `thinc 9.x` zieht – für Python 3.13 gibt es -keine thinc-9-Wheels. Deshalb wird `kokoro` mit `--no-deps` und `misaki` -ohne `[en]` installiert; die deutsche G2P läuft über `espeak-ng` und braucht -spacy nicht. +**Hinweis (Python 3.13):** Der semidark/kokoro-Fork (0.9.4) unterstützt +Python 3.13 nativ. Der semidark/misaki-Fork (0.9.4) nutzt für den deutschen +Pfad `phonemizer-fork` + `espeakng-loader` (kein spacy-curated-transformers, +kein thinc 9.x). `spacy` wird nur für den `misaki.en`-Import benötigt +(Englisch), nicht für den deutschen Pfad. ## Repository-Struktur diff --git a/deploy/install.sh b/deploy/install.sh index ac6fdea..5f6c4f6 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -80,7 +80,7 @@ if ! command -v espeak-ng >/dev/null 2>&1; then apt-get install -y espeak-ng fi -# Kokoro-Venv (CPU-only torch + kokoro + misaki + phonemizer + soundfile + lameenc) +# Kokoro-Venv (CPU-only torch + semidark/kokoro + semidark/misaki + soundfile + lameenc) if [ ! -x "$KOKORO_VENV/bin/python" ]; then echo "-- Erstelle Kokoro-Venv in $KOKORO_VENV" mkdir -p "$KOKORO_VENV" @@ -91,12 +91,17 @@ if [ ! -x "$KOKORO_VENV/bin/python" ]; then --index-url https://download.pytorch.org/whl/cpu echo "-- Installiere Kokoro-Abhängigkeiten" "$KOKORO_VENV/bin/pip" install --quiet \ - huggingface-hub loguru scipy transformers regex num2words \ - phonemizer soundfile lameenc - # kokoro ohne [en]-Extra (vermeidet thinc 9.x, das kein Py3.13-Wheel hat); - # deutsche G2P läuft über espeak-ng (phonemizer), nicht über spacy. - "$KOKORO_VENV/bin/pip" install --quiet kokoro --no-deps - "$KOKORO_VENV/bin/pip" install --quiet misaki + huggingface-hub loguru transformers regex num2words \ + soundfile lameenc + # Offizieller Kikiri-Deutsche-Pfad: + # - semidark/misaki-Fork (0.9.4) mit [de]-Extra (phonemizer-fork + espeakng-loader) + # - semidark/kokoro-Fork (0.9.4) mit --no-deps (vermeidet misaki[en] → spacy-curated-transformers) + # - spacy + num2words für misaki.en-Import (Englisch, nicht für deutschen Pfad) + "$KOKORO_VENV/bin/pip" install --quiet "spacy<4" + "$KOKORO_VENV/bin/pip" install --quiet \ + "misaki[de] @ git+https://github.com/semidark/misaki.git" + "$KOKORO_VENV/bin/pip" install --quiet \ + "kokoro @ git+https://github.com/semidark/kokoro.git" --no-deps fi # Kokoro-Modelle (kikiri-german-martin + kikiri-german-victoria, Apache 2.0) diff --git a/router/tts_worker.py b/router/tts_worker.py index 3e5b0ed..7d1249e 100644 --- a/router/tts_worker.py +++ b/router/tts_worker.py @@ -7,6 +7,11 @@ RAM (CPU-only, niedrige Warm-Start-Latenz). Wird als eigener systemd-Service betrieben und vom AI Profile Router über HTTP angesprochen (POST /v1/audio/speech -> POST /tts). +Nutzt den offiziellen Kikiri-Deutsche-Inferenzpfad: +- semidark/kokoro-Fork (0.9.4) mit lang_code='d' +- semidark/misaki-Fork (0.9.4) mit misaki.de.DEG2P + (Text-Normalisierung + espeak-ng + Aussprache-Overrides) + API: GET /status -> {"status":"ok","ready":bool,"voices":[...],...} POST /tts -> {"text":"...","voice":"martin","speed":1.0, @@ -74,22 +79,28 @@ class TTSWorker: self.total_requests = 0 def load(self) -> None: - """Lädt alle Stimmen (CPU-only).""" + """Lädt alle Stimmen (CPU-only) via offiziellem Kikiri-Deutsche-Pfad. + + Nutzt den semidark/kokoro-Fork (0.9.4) mit lang_code='d' und + den semidark/misaki-Fork (0.9.4) mit misaki.de.DEG2P + (Text-Normalisierung + espeak-ng + Aussprache-Overrides). + """ import torch from kokoro import KModel, KPipeline - # Deutsche Sprachunterstützung (kokoro PR #340): 'de' -> espeak-ng G2P. - from kokoro import pipeline as _pipeline_mod - _pipeline_mod.ALIASES.setdefault("de", "d") - _pipeline_mod.LANG_CODES.setdefault("d", "de") for name, cfg in VOICES.items(): t0 = time.monotonic() try: kmodel = KModel( + repo_id="hexgrad/Kokoro-82M", config=os.path.join(MODEL_DIR, cfg["config"]), model=os.path.join(MODEL_DIR, cfg["model"]), ).to("cpu").eval() - pipeline = KPipeline(lang_code="de", model=kmodel) + pipeline = KPipeline( + lang_code="d", + repo_id="hexgrad/Kokoro-82M", + model=kmodel, + ) voice = torch.load( os.path.join(MODEL_DIR, cfg["voice"]), map_location="cpu", weights_only=True)