chatterbox-tts-cli/README.md
dschlueter 34a34907a8 Bugfixes, Verbesserungen und Mixed-Language-Support
Bugfixes:
- Abkürzungen (z.B., d.h., Dr., Prof.) werden nicht mehr als Satzenden erkannt (_ABBREV_MASK_RE)
- Multilingual-Import: except Exception → except (ImportError, ModuleNotFoundError)
- tts_agent: ReAct-Schleife auf max. 10 Iterationen begrenzt, model_dump → explizites Dict
- tts_service: audio_device=None fällt auf 'pulse' zurück
- JSON-Fehlerbehandlung für --pronunciation-dict mit aussagekräftiger Meldung
- PlaybackWorker: Audio-Device wird vor Stream-Start via sd.query_devices() geprüft
- mcp_adapter: Fehlerbehandlung für HTTP-Fehler, Timeout erhöht, session_id ergänzt
- tts_agent: Health-Check beim Start, --speed/--first-chunk-len Validierung

Neue Features:
- Gemischtsprachige Texte: [en]...[/en]-Markierungen für per-Segment language_id
- strip_markdown(): entfernt Markdown-Formatierung vor der Synthese (--no-strip-markdown)
- Emoji-Entfernung in clean_raw_text() via unicodedata
- Pause/Resume: request_pause()/request_resume(), POST /pause, POST /resume, MCP-Tools
- Neue Einheiten: °C, °F, kWh, kW, W, V, A, J, kPa, bar, m², m³, m/s, rpm
- number_to_words_de/en bis Milliarden
- DEFAULT_PRONUNCIATION_DE erweitert (GitHub, YouTube, LinkedIn, Wi-Fi, iPhone, ChatGPT, …)
- NON_SPELLED_ACRONYMS erweitert (USB, CPU, GPU, API, CEO, HTML, …)
- Nummerierte Listen als separate Chunks behandelt
- Modell-Warmup via TTS_PRELOAD_LANG Env-Variable
- requirements.txt: Upper-Bounds für fastapi und uvicorn

Dokumentation: CLAUDE.md, README.md, BEDIENUNGSANLEITUNG.md vollständig aktualisiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 11:36:54 +02:00

12 KiB
Raw Blame History

chatterbox-tts-cli

Ein lokaler Text-to-Speech-Assistent auf Basis von Chatterbox TTS (Resemble AI). Optimiert für deutsche Sprache; nutzbar als Kommandozeilen-Tool, als lokaler HTTP-Service und als MCP-Server für KI-Assistenten.

Features

  • Satz-für-Satz-Ausgabe — gibt den ersten Satz aus, während die nächsten bereits generiert werden; minimale Latenz
  • Lückenlose Audiowiedergabe — Callback-basierter OutputStream; keine Unterbrechungen zwischen Sätzen
  • Pause/Resume — Ausgabe pausieren und fortsetzen ohne Datenverlust (POST /pause, POST /resume)
  • Geschwindigkeitsanpassung — pitch-erhaltende Zeitstreckung via pyrubberband (R3-Engine); --speed 0.52.0
  • Voice Cloning — optionale WAV-Referenz für Akzent und Klang
  • Mehrsprachig — Deutsch, Englisch und 20+ weitere Sprachen via ChatterboxMultilingualTTS
  • Gemischtsprachige Texte[en]...[/en]-Markierungen für englische Passagen in deutschen Texten
  • Deutsche Textnormalisierung — Abkürzungen (ARD → „Ah Er De"), Uhrzeiten (14:58 → „vierzehn Uhr achtundfünfzig"), Jahreszahlen bis Milliarden, Einheiten (°C, °F, kWh, m², …), Aussprache-Wörterbuch
  • Markdown-Bereinigung — entfernt **fett**, # Überschrift, Links, Code-Blöcke automatisch vor der Synthese
  • HTTP-Service — FastAPI-Service mit Job-Queue, Stop/Pause/Interrupt, Status-Endpunkt
  • MCP-Adapter — direkte Integration in Claude Code, Claude Desktop und andere MCP-Hosts
  • Systemd-Autostart — Service startet automatisch beim Login

Systemvoraussetzungen

  • Python 3.11+
  • CUDA-GPU empfohlen (RTX 3070 oder besser; CPU möglich, aber langsam)
  • Linux mit PipeWire oder PulseAudio
  • rubberband-cli für Geschwindigkeitsanpassung:
    sudo apt install rubberband-cli
    

Installation

# 1. Conda-Umgebung
conda create -n chatterbox python=3.11
conda activate chatterbox

# 2. PyTorch mit CUDA (Beispiel CUDA 12.4)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu124

# 3. Alle Abhängigkeiten
pip install -r requirements.txt

Beim ersten Start mit --lang de werden Modelle automatisch heruntergeladen (~23 GB, ~/.cache/huggingface/).


Kommandozeilen-CLI

conda activate chatterbox

# Deutschen Text vorlesen
python chatterbox_cli_v4.py --lang de --input text.txt

# Mit Voice Cloning
python chatterbox_cli_v4.py --lang de --voice stimme.wav --input text.txt

# Text direkt übergeben
python chatterbox_cli_v4.py --lang en --text "Hello, how are you?"

# Langsamer sprechen (pitch bleibt gleich)
python chatterbox_cli_v4.py --lang de --speed 0.85 --input text.txt

# Nur speichern, nicht abspielen
python chatterbox_cli_v4.py --lang de --no-play --output ausgabe.wav --input text.txt

# Aussprache-Wörterbuch
python chatterbox_cli_v4.py --lang de --pronunciation-dict aussprache.json --input text.txt

# Gemischtsprachiger Text
python chatterbox_cli_v4.py --lang de --text \
  "Das [en]Machine Learning[/en] Modell kostet ca. 50 €."

# Markdown-Bereinigung deaktivieren
python chatterbox_cli_v4.py --lang de --no-strip-markdown --input text.txt

CLI-Optionen

Option Standard Beschreibung
--text TEXT Text direkt als Argument
--input DATEI UTF-8-Textdatei
--lang CODE de Sprachcode (de, en, fr, es, …)
--voice DATEI.wav Referenz-WAV für Voice Cloning (1030 s)
--speed N 1.0 Wiedergabegeschwindigkeit (0.52.0)
--audio-device pulse Ausgabegerät (z. B. pulse, default)
--t3-model v3 Multilingual-Modell: v3 oder v2
--acronym-mode german Akronym-Modus: german, space, period_space
--pronunciation-dict JSON-Datei mit Aussprache-Substitutionen
--no-strip-markdown Markdown-Formatierung nicht entfernen
--save nein WAV-Datei speichern
--output DATEI.wav Ausgabepfad (impliziert --save)
--no-play Nicht live abspielen
--no-sentence-mode Größere Chunks statt satzweise
--stream Streaming-Modus (experimentell)
--no-progress Weniger Konsolenausgabe
--debug-delay N 0 Pause vor jedem Satz (zum Testen)
--stop Laufende Ausgabe abbrechen

Gemischtsprachige Texte

Deutsche Texte enthalten oft englische Fachbegriffe, Markennamen oder Zitate. Mit [xx]...[/xx]-Markierungen werden diese Passagen mit der richtigen language_id an das Multilingual-Modell übergeben:

Das [en]Machine Learning[/en] Framework kostet ca. 50 €.
Der [en]CEO[/en] sagte: [en]"We are committed to innovation."[/en]

Ohne Markierungen verhält sich das System identisch wie bisher.

Häufige englische Tech-Begriffe werden bereits automatisch korrekt ausgesprochen (eingebaut in DEFAULT_PRONUNCIATION_DE):

Begriff Aussprache
GitHub „Git Hab"
YouTube „Jutjub"
LinkedIn „Linked In"
Wi-Fi „Wai Fai"
iPhone „Aiphone"
ChatGPT „Tschet Dschie Pie Tie"

HTTP-Service (tts_service.py)

FastAPI-Service mit Job-Queue und Worker-Thread. Startet automatisch via systemd.

# Manueller Start
uvicorn tts_service:app --host 0.0.0.0 --port 9999

# Mit Modell-Warmup (kein Cold-Start beim ersten Request)
TTS_PRELOAD_LANG=de uvicorn tts_service:app --host 0.0.0.0 --port 9999

# Systemd (Autostart, läuft bereits)
systemctl --user status chatterbox-tts
systemctl --user restart chatterbox-tts
journalctl --user -u chatterbox-tts -f

Endpunkte

Methode Pfad Funktion
POST /speak Text in Queue einreihen
POST /stop Ausgabe abbrechen, Queue leeren
POST /pause Ausgabe pausieren (ohne Datenverlust)
POST /resume Pausierte Ausgabe fortsetzen
GET /health Service-Status und Gerät
GET /status Aktueller Job, Queue-Länge, letzte Jobs
GET /voices Unterstützte Sprachen

/speak Request-Body

{
  "text": "Hallo Welt",
  "lang": "de",
  "voice": null,
  "interrupt": false,
  "speed": 1.0,
  "t3_model": "v3",
  "audio_device": null,
  "max_len": 400,
  "save_wav": false,
  "output_path": null,
  "pronunciation_dict": null,
  "session_id": null
}
# Beispiel
curl -X POST http://localhost:9999/speak \
  -H "Content-Type: application/json" \
  -d '{"text": "Hallo Welt", "lang": "de"}'

# Aus dem LAN
curl -X POST http://192.168.x.x:9999/speak \
  -H "Content-Type: application/json" \
  -d '{"text": "Text aus dem Netzwerk", "lang": "de"}'

# Laufende Ausgabe unterbrechen
curl -X POST http://localhost:9999/speak \
  -H "Content-Type: application/json" \
  -d '{"text": "Wichtiger Text", "lang": "de", "interrupt": true}'

# Pausieren und fortsetzen
curl -X POST http://localhost:9999/pause
curl -X POST http://localhost:9999/resume

# Stoppen
curl -X POST http://localhost:9999/stop

MCP-Adapter (mcp_adapter.py)

Dünner Wrapper über die REST-API für MCP-fähige Hosts.

# stdio-Modus (Claude Code / Claude Desktop)
python mcp_adapter.py --stdio

# HTTP-Modus (andere MCP-Clients, Port 8001)
python mcp_adapter.py

# Anderen TTS-Service ansprechen
TTS_URL=http://192.168.1.10:9999 python mcp_adapter.py --stdio

MCP-Tools

Tool Parameter Funktion
speak text, lang, voice, interrupt, speed, session_id Text ausgeben
stop Ausgabe stoppen und Queue leeren
pause Ausgabe pausieren (ohne Datenverlust)
resume Pausierte Ausgabe fortsetzen
get_status Aktuellen Job und Queue abfragen
list_voices Unterstützte Sprachen auflisten

Claude Code Konfiguration

Bereits eingerichtet via claude mcp add --scope user. Zur manuellen Einrichtung:

claude mcp add --scope user chatterbox-tts \
  /home/dschlueter/miniforge3/envs/chatterbox/bin/python \
  /home/dschlueter/chatterbox-tts-cli/mcp_adapter.py --stdio

Claude Desktop (~/.config/claude/claude_desktop_config.json)

{
  "mcpServers": {
    "chatterbox-tts": {
      "command": "/home/dschlueter/miniforge3/envs/chatterbox/bin/python",
      "args": ["/home/dschlueter/chatterbox-tts-cli/mcp_adapter.py", "--stdio"]
    }
  }
}

Integration mit KI-Tools

Claude Code / Claude Desktop — MCP (fertig eingerichtet)

Claude kann direkt die Tools speak, stop, pause, resume, get_status und list_voices aufrufen. Kein weiterer Setup nötig.

Ollama (llama3.2, qwen2.5, mistral-nemo u. a.)

Modelle mit Tool-Support können den REST-Service über Function Calling ansprechen:

import ollama, httpx

tools = [{
    "type": "function",
    "function": {
        "name": "speak",
        "description": "Text als Sprache ausgeben",
        "parameters": {
            "type": "object",
            "properties": {
                "text": {"type": "string"},
                "lang": {"type": "string", "default": "de"},
                "speed": {"type": "number", "default": 1.0},
            },
            "required": ["text"],
        },
    },
}]

resp = ollama.chat(model="qwen2.5", messages=[{"role": "user", "content": "..."}], tools=tools)

for call in resp.message.tool_calls or []:
    if call.function.name == "speak":
        httpx.post("http://127.0.0.1:9999/speak", json=call.function.arguments)

TTS Agent (tts_agent.py)

Eigenständiger Konversationsagent mit eingebautem Function Calling:

# Mit Ollama
python tts_agent.py --model qwen2.5

# Mit LM Studio
python tts_agent.py --base-url http://localhost:1234/v1 --model local-model

# Mit OpenAI
OPENAI_API_KEY=sk-... python tts_agent.py --model gpt-4o

# Mit Voice Cloning
python tts_agent.py --model qwen2.5 --voice my_voice.wav

Open WebUI

Im Open-WebUI-Menü unter Tools eine neue Python-Klasse anlegen:

import requests

class Tools:
    def speak(self, text: str, lang: str = "de") -> str:
        """Text als Sprache ausgeben."""
        r = requests.post("http://127.0.0.1:9999/speak",
                          json={"text": text, "lang": lang}, timeout=10)
        return r.json().get("job_id", "error")

    def stop(self) -> str:
        """Laufende Sprachausgabe stoppen."""
        requests.post("http://127.0.0.1:9999/stop", timeout=5)
        return "stopped"

Home Assistant

# configuration.yaml
rest_command:
  tts_speak:
    url: "http://192.168.x.x:9999/speak"
    method: POST
    content_type: "application/json"
    payload: '{"text": "{{ text }}", "lang": "de"}'

  tts_stop:
    url: "http://192.168.x.x:9999/stop"
    method: POST

  tts_pause:
    url: "http://192.168.x.x:9999/pause"
    method: POST

  tts_resume:
    url: "http://192.168.x.x:9999/resume"
    method: POST

Aufruf in einer Automation:

service: rest_command.tts_speak
data:
  text: "Die Waschmaschine ist fertig."

Node-RED / n8n

HTTP-Request-Node direkt auf POST http://<host>:9999/speak mit JSON-Body. Kein weiterer Setup nötig.


Aussprache-Wörterbuch

Für Namen oder Begriffe, die das Modell falsch ausspricht:

{
  "Xi Jinping": "Schi Dschinping",
  "Putin": "Pjutin",
  "Seoul": "Söul",
  "Kubernetes": "Kubernetis"
}
python chatterbox_cli_v4.py --lang de \
  --pronunciation-dict aussprache.json \
  --input nachricht.txt

Häufige Begriffe sind bereits eingebaut (GitHub, YouTube, iPhone, Xi Jinping u. a.). Das eigene Dict wird immer nach dem eingebauten angewendet — Überschreibungen sind möglich.


Bekannte Einschränkungen

  • Wortbetonung lässt sich nicht steuern — kein SSML. Abhilfe: Voice-Referenz mit gewünschter Betonung.
  • Laufendes model.generate() kann nicht mid-call abgebrochen werden (Python-Thread-Grenzen); Stop/Pause greift am nächsten Chunk-Beginn.
  • Sprachmarkierungen [en]...[/en] funktionieren nur mit ChatterboxMultilingualTTS; bei --lang en (mono) werden sie ignoriert.
  • Streaming-Modus unterstützt keine Sprachmarkierungen.

Lizenz

MIT — dieses Skript. Das Chatterbox-Modell: MIT-Lizenz (Resemble AI). Modellgewichte: CC BY-NC 4.0.