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>
37 lines
1.3 KiB
Python
37 lines
1.3 KiB
Python
"""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 1–31
|
||
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"
|