feat(tts): Aussprache-Lexikon befüllt (verifizierte Vokallängen-Fixes) + case-insensitiv

terms-Matching jetzt case-insensitiv (Aussprache ist case-egal -> ein Eintrag
deckt auch Satzanfaenge ab). config/pronunciation.de.yaml mit per espeak-ng
verifizierten Korrekturen gefuellt: stroemt/stroemte/loest/toent/blaest/buesst/
gruesst/Mond -> lange Vokale (h-Umschreibung). Kontrolle: loescht/waescht/stroemst
bleiben korrekt unangetastet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-17 23:19:17 +02:00
commit 449a62a88e
3 changed files with 30 additions and 6 deletions

View file

@ -112,12 +112,15 @@ def _apply_units(text: str, units: dict) -> str:
return text
def _apply_dict(text: str, mapping: dict) -> str:
def _apply_dict(text: str, mapping: dict, ignore_case: bool = False) -> str:
# Längste Schlüssel zuerst, wortgrenzen-bewusst (Abkürzungen enden oft auf ".").
flags = re.IGNORECASE if ignore_case else 0
for key in sorted(mapping, key=len, reverse=True):
repl = mapping[key]
if key.isalnum(): # reines Wort/Akronym -> mit Wortgrenzen
text = re.sub(rf"\b{re.escape(key)}\b", repl, text)
text = re.sub(rf"\b{re.escape(key)}\b", repl, text, flags=flags)
elif ignore_case:
text = re.sub(re.escape(key), repl, text, flags=re.IGNORECASE)
else: # enthält Punkte/Sonderzeichen -> direkte Ersetzung
text = text.replace(key, repl)
return text
@ -143,12 +146,12 @@ class TTSNormalizer:
t = _apply_ordinals(t)
t = _apply_units(t, {**_DEFAULT_UNITS_DE, **units})
t = _apply_dict(t, {**_DEFAULT_ABBREVS_DE, **abbrevs})
t = _apply_dict(t, terms)
t = _apply_dict(t, terms, ignore_case=True)
t = _apply_dict(t, _DEFAULT_SYMBOLS_DE)
else:
t = _apply_units(t, units)
t = _apply_dict(t, abbrevs)
t = _apply_dict(t, terms)
t = _apply_dict(t, terms, ignore_case=True)
t = _apply_dict(t, _DEFAULT_SYMBOLS_EN)
# Slash zwischen Wörtern/Zahlen sprachfreundlich, Striche entschärfen.