Aussprache-Wörterbuch: eigenes Modul, Wortgrenzen, gepflegte Liste, Kandidaten-Suche

Englische Fachbegriffe und fremde Eigennamen wurden auf Deutsch falsch vorgelesen
("Repository", "Donald Trump"). Chatterbox hat keinen Lautschrift-Eingang, also bleibt
nur die Umschrift in deutscher Rechtschreibung — die gab es zwar schon, aber nur als
kleines Dict im CLI-Skript, das keine andere Anwendung sinnvoll erweitern konnte.

Empirisch geprüft, warum es keinen besseren Weg gibt:
- Der multilinguale Tokenizer heißt "grapheme_mtl_merged_expanded_v1" und enthält zwar
  IPA-Zeichen und ein [ipa]-Sprachtoken. generate() lehnt language_id="ipa" ab; umgeht
  man nur die Whitelist, kommt Unsinn heraus: "ɹɪˈpɑzɪˌtɔɹi" klingt wie "Ripacitari",
  "dɪˈplɔɪmənt" wie "Deep Romant" (per Whisper zurücktranskribiert). IPA ist tot.
- Der vorhandene Sprachwechsel im Satz ([en]...[/en]) synthetisiert die Teile korrekt,
  klebt sie aber ohne Überblendung zusammen: gemessen 4 Nahtpausen von 0,5-0,8 s, der
  Satz wächst von 3,9 s auf 7,1 s. Für Fließtext unbrauchbar.

Neu:
- pronunciation.py — eigenständiges Modul, reine Standardbibliothek (kein torch), damit
  CLI, HTTP-Service, MCP-Adapter und fremde Projekte (Open Notebook) dasselbe Wörterbuch
  nutzen können, ohne das Modell zu laden. Namen werden aus chatterbox_cli_v4
  re-exportiert, bestehende Importe bleiben gültig.
- Ladereihenfolge mit Vorrang: eingebaut -> pronunciation/<lang>.json (mitgeliefert) ->
  ~/.config/chatterbox/pronunciation/<lang>.json -> $CHATTERBOX_PRONUNCIATION_DICT ->
  explizit übergebenes Dict. Kaputte JSON-Dateien werden gemeldet, nicht fatal.
- pronunciation/de.json — kuratierte Einträge (Tech, KI, Firmen, Personen, Medien).
- pronunciation_candidates.py — findet in einem Text alles, was hunspell (de) nicht kennt
  und noch nicht im Wörterbuch steht. An einem echten Podcast-Transkript getestet: 61
  Kandidaten, darunter Voicebox, Scrapling, Scraping.

Fehlerbehebung: Ersetzt wird jetzt an Wortgrenzen und in einem einzigen Durchgang. Das
alte str.replace() machte aus "UNESCO" ein "Uh EnnESCO" und aus "UNIX" ein "Uh EnnIX",
weil der Eintrag "UN" auch mitten im Wort traf.

Verifiziert: 199 Einträge laden in 44 ms ohne torch; UNESCO/UNIX/Xiaomi bleiben intakt;
Open Notebooks TTS-Server spricht die Umschrift ohne eine einzige Codeänderung dort; der
MCP-Service auf :9999 läuft unverändert weiter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-07-11 16:52:37 +02:00
commit cd9383ff88
6 changed files with 570 additions and 50 deletions

View file

@ -2,6 +2,7 @@
import argparse
import importlib.util
import json
import queue
import re
import sys
@ -187,47 +188,15 @@ UNIT_REPLACEMENTS = {
"%": "Prozent",
}
# Eingebaute phonetische Annäherungen für häufige Fremdnamen und Anglizismen (Deutsch).
# Nur Begriffe aufnehmen, bei denen das deutsche TTS eine falsche Aussprache produziert.
# Anglizismen wie "Cloud", "Update", "Meeting" klingen auf Deutsch akzeptabel → kein Eintrag.
DEFAULT_PRONUNCIATION_DE: dict[str, str] = {
# Chinesische Eigennamen
"Xi Jinping": "Schi Jinping",
"Xi": "Schi",
"Jinping": "Jinping",
"Peking": "Peking",
# Tech-Markennamen mit problematischer Aussprache
"GitHub": "Git Hab",
"LinkedIn": "Linked In",
"YouTube": "Jutjub",
"Wi-Fi": "Wai Fai",
"iPhone": "Aiphone",
"MacBook": "Mäk Buk",
"ChatGPT": "Tschet Dschie Pie Tie",
"OpenAI": "Open A I",
"Anthropic": "Enthropik",
"Claude": "Kloode",
# KI-Begriffe
"GPT": "Dschie Pie Tie",
"LLM": "El El Em",
# Sonstige
"UN": "Uh En",
"ARD": "Ah Er Dee",
"ZDF": "Tset De Eff",
"RTL": "Er Te El",
"AFD": "Ah Eff Dee",
"AfD": "Ah Eff Dee",
"CDU": "Tse De Uh",
"SPD": "Es Pe Dee",
"FDP": "Eff De Pee",
"BSW": "Be Es Wee",
}
def apply_pronunciation_dict(text: str, pron_dict: dict[str, str]) -> str:
for phrase, replacement in sorted(pron_dict.items(), key=lambda x: len(x[0]), reverse=True):
text = text.replace(phrase, replacement)
return text
# Aussprache-Wörterbuch: liegt in pronunciation.py (ohne torch-Abhängigkeit, damit
# es auch schlanke Werkzeuge und fremde Anwendungen nutzen können). Die Namen werden
# hier re-exportiert, damit bestehende Importe von chatterbox_cli_v4 weiter greifen.
from pronunciation import ( # noqa: E402
DEFAULT_PRONUNCIATION_DE,
PRONUNCIATION_ENV,
apply_pronunciation_dict,
load_pronunciation_dict,
)
import unicodedata as _unicodedata
@ -591,11 +560,12 @@ def preprocess_tts_text(
if acronym_mode is None:
acronym_mode = "german" if lang == "de" else "period_space"
# 1. Aussprache-Wörterbuch zuerst (vor Akronym-Expansion, damit Eigennamen greifen)
if lang == "de":
text = apply_pronunciation_dict(text, DEFAULT_PRONUNCIATION_DE)
if pronunciation_dict:
text = apply_pronunciation_dict(text, pronunciation_dict)
# 1. Aussprache-Wörterbuch zuerst (vor Akronym-Expansion, damit Eigennamen greifen).
# load_pronunciation_dict() fuegt eingebaute, mitgelieferte, benutzereigene und
# per Umgebungsvariable gesetzte Eintraege zusammen; `pronunciation_dict` (vom
# Aufrufer) hat Vorrang. In EINEM Durchgang ersetzen, damit eine Ersetzung nicht
# erneut von einem anderen Eintrag getroffen wird.
text = apply_pronunciation_dict(text, load_pronunciation_dict(lang, pronunciation_dict))
if normalize_units_values:
text = normalize_units(text, lang)