Ein lokaler Text-to-Speech-Assistent auf Basis von [Chatterbox TTS](https://github.com/resemble-ai/chatterbox) (Resemble AI). Optimiert für deutsche Sprache; nutzbar als Kommandozeilen-Tool, als lokaler HTTP-Service und als MCP-Server für KI-Assistenten.
Find a file
dschlueter 7893c60e53 Dokumentation: Datum-Normalisierung und Normalisierungs-Übersicht ergänzt
- README: Feature-Liste, CLI-Optionen (--no-normalize-*), Tabelle aller
  Normalisierungsschritte mit Beispielen
- BEDIENUNGSANLEITUNG: Datumsformat in "Was das Programm automatisch macht"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 01:33:49 +02:00
.gitignore CLAUDE.md aus Versionskontrolle entfernen und ignorieren 2026-06-03 11:43:30 +02:00
BEDIENUNGSANLEITUNG.md Dokumentation: Datum-Normalisierung und Normalisierungs-Übersicht ergänzt 2026-06-04 01:33:49 +02:00
chatterbox_cli_v4.py Datum-Normalisierung: DD.MM.YYYY → deutsche Ordinalform 2026-06-03 23:45:03 +02:00
LICENSE Initial commit 2026-06-03 11:35:27 +02:00
mcp_adapter.py Audio-Download-Endpunkt GET /audio/{job_id} hinzufügen 2026-06-03 21:09:06 +02:00
README.md Dokumentation: Datum-Normalisierung und Normalisierungs-Übersicht ergänzt 2026-06-04 01:33:49 +02:00
requirements.txt Bugfixes, Verbesserungen und Mixed-Language-Support 2026-06-03 11:36:54 +02:00
Trump_in_China_kurz.txt Initial commit: chatterbox TTS CLI v4 2026-05-16 08:56:50 +02:00
tts_agent.py Bugfixes, Verbesserungen und Mixed-Language-Support 2026-06-03 11:36:54 +02:00
tts_service.py Audio-Download-Endpunkt GET /audio/{job_id} hinzufügen 2026-06-03 21:09:06 +02:00

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 — Datumsangaben (03.06.2026 → „Dritter Sechster Zwanzigsechsundzwanzig"), Uhrzeiten (14:58 → „vierzehn Uhr achtundfünfzig"), Jahreszahlen bis Milliarden, Einheiten (°C, °F, kWh, m², …), Abkürzungen, 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
--no-normalize-dates Datumsangaben nicht in Ordinalform umwandeln
--no-normalize-times Uhrzeiten nicht umwandeln
--no-normalize-years Jahreszahlen nicht umwandeln
--no-normalize-units Einheiten nicht umwandeln
--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

Voice Cloning — Stimme aufnehmen

Für Voice Cloning braucht Chatterbox eine WAV-Aufnahme von 1060 Sekunden in ruhiger Umgebung.

Aufnahme-Workflow

# 1. Verfügbare Mikrofon-Eingänge anzeigen
pactl list sources short | grep -v monitor

# 2. Trainingstext in der Datei anzeigen / lesen
cat ~/chatterbox-tts-cli/Trainings_Text.txt

# 3. Aufnahme starten — 60 Sekunden, stoppt automatisch
#    (nutzt das Standard-Eingabegerät von PipeWire/PulseAudio)
arecord -D pulse -f S16_LE -r 48000 -c 1 --duration=60 \
  ~/chatterbox-tts-cli/my_voice_deutsch_60s.wav

# 4. Aufnahme abhören und prüfen
aplay ~/chatterbox-tts-cli/my_voice_deutsch_60s.wav

# 5. Als Voice-Profil nutzen
conda activate chatterbox
python chatterbox_cli_v4.py --lang de \
  --voice my_voice_deutsch_60s.wav \
  --text "Testtext mit meiner Stimme."

Bestimmtes Mikrofon auswählen (z. B. MOTU M2)

# Quellname des M2 herausfinden
pactl list sources short | grep -v monitor

# Aufnahme explizit vom MOTU M2:
arecord -D pulse \
  --default-device=alsa_input.usb-MOTU_M2_M20000046918-00.analog-stereo \
  -f S16_LE -r 48000 -c 1 --duration=60 \
  ~/chatterbox-tts-cli/my_voice_deutsch_60s.wav

Tipps für gute Aufnahmen

  • Ruhige Umgebung, kein Hintergrundlärm
  • Normaler Gesprächsabstand zum Mikrofon (2040 cm)
  • Gleichmäßiges, natürliches Sprechtempo
  • 3060 Sekunden sind ideal; 10 Sekunden sind das Minimum

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 /audio/{job_id} Fertige WAV herunterladen (nur mit keep_audio=true)
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,
  "keep_audio": false
}
# 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}'

# WAV-Datei erzeugen und herunterladen
JOB=$(curl -s -X POST http://localhost:9999/speak \
  -H "Content-Type: application/json" \
  -d '{"text": "Hallo Welt", "lang": "de", "keep_audio": true}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
sleep 40  # warten bis Synthese fertig
curl -o ausgabe.wav http://localhost:9999/audio/$JOB
# → WAV-Datei; wird nach dem Download automatisch gelöscht

# 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, keep_audio 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.


Textnormalisierung im Überblick

Die Normalisierungspipeline läuft automatisch vor der TTS-Synthese (nur --lang de):

Schritt Beispiel Eingabe Beispiel Ausgabe
Aussprache-Dict „Xi Jinping" „Schi Jinping"
Einheiten „25 °C", „100 kWh", „10 m²" „25 Grad Celsius", „100 Kilowattstunde", „10 Quadratmeter"
Datum „03.06.2026" „Dritter Sechster Zwanzigsechsundzwanzig"
Uhrzeit „14:58 Uhr" „vierzehn Uhr achtundfünfzig"
Jahreszahl „2026" „zweitausendsechsundzwanzig"
Akronyme „ARD", „CPU" „Ah Er De", „C P U"

Jeder Schritt kann einzeln deaktiviert werden: --no-normalize-dates, --no-normalize-times, --no-normalize-years, --no-normalize-units, --no-spell-acronyms


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.