my_voice_assistant_v2/app/pipeline/german_numbers.py
Dieter Schlüter c9d8552ec7 feat(tts): Aussprache-Normalisierung vor Piper (Ordinalia/Einheiten/Abk./Lexikon)
In-Process-Layer ausgebaut statt neuer Lib/CLI. Leitprinzip: nicht duplizieren,
was espeak-ng schon kann (Kardinal-/Dezimalzahlen bleiben unangetastet) -- nur die
belegten Luecken fuellen.

- german_numbers.py: deutsche Ordinalzahlen 1.-31. (attributiv/adverbial)
- tts_normalizer.py: Ordinalia (Datum '1. Mai'->'erster Mai', Folgen '1. 2. 3.'->
  'erstens, zweitens, ...'), Einheiten nach Zahl (kg/km/km-h/...), Abkuerzungen
  (Dr./z.B./usw.), optionales YAML-Lexikon (config/pronunciation.<lang>.yaml).
  Provider-abhaengige Stufen auto|full|light|off (TTS_NORMALIZE_LEVEL): piper=full,
  Cloud=light (laesst Zahlen/Abk. fuer das Cloud-Modell in Ruhe).
- spoken_response_adapter.py: nummerierte Listen -> Ordinalwoerter statt Loeschen.
- sentence_chunker.py: trennt nicht mehr nach Ziffer+Punkt, Einzelbuchstabe+Punkt
  ('z. B.', Initialen) oder bekannten Abkuerzungen -> behebt das Streaming-Symptom
  ('1.' wurde als eigener 'Satz' zu 'eins').
- orchestrator/dependencies: normalize_level durchgereicht (auto: piper->full).
- Tests: tests/test_tts_normalizer.py + Chunker-Faelle (85 gruen).
- Doku: BEDIENUNGSANLEITUNG (Aussprache verbessern), .env.example.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:01:41 +02:00

37 lines
1.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Deutsche Ordinalzahlen 1.31. (für Datums- und Aufzählungs-Aussprache).
Bewusst eine kleine handgepflegte Tabelle statt `num2words`: die deutsche
Ordinal-Flexion ist mit num2words nicht sauber abbildbar, und der Bereich 131
deckt Datumsangaben und Listenpositionen vollständig ab.
"""
from __future__ import annotations
# Stamm der Ordinalzahl (ohne Endung). attributiv = Stamm + "er" ("erster"),
# adverbial = Stamm + "ens" ("erstens").
_STEMS: dict[int, str] = {
1: "erst", 2: "zweit", 3: "dritt", 4: "viert", 5: "fünft",
6: "sechst", 7: "siebt", 8: "acht", 9: "neunt", 10: "zehnt",
11: "elft", 12: "zwölft", 13: "dreizehnt", 14: "vierzehnt", 15: "fünfzehnt",
16: "sechzehnt", 17: "siebzehnt", 18: "achtzehnt", 19: "neunzehnt", 20: "zwanzigst",
21: "einundzwanzigst", 22: "zweiundzwanzigst", 23: "dreiundzwanzigst",
24: "vierundzwanzigst", 25: "fünfundzwanzigst", 26: "sechsundzwanzigst",
27: "siebenundzwanzigst", 28: "achtundzwanzigst", 29: "neunundzwanzigst",
30: "dreißigst", 31: "einunddreißigst",
}
MIN, MAX = 1, 31
def has_ordinal(n: int) -> bool:
return n in _STEMS
def ordinal_attributive(n: int) -> str:
"""'1' -> 'erster' (z. B. 'erster Mai')."""
return _STEMS[n] + "er"
def ordinal_adverbial(n: int) -> str:
"""'1' -> 'erstens' (Aufzählungen)."""
return _STEMS[n] + "ens"