llmrouter: Sprechtext-Normalisierung vor TTS — Postleitzahl als Ziffernfolge mit Pause
"Bergstraße 7, 83646 Bad Tölz" -> "Bergstraße 7; Postleitzahl 8 3 6 4 6, Bad Tölz" (Andreas 2026-09-06, Variante 4 nach Hörtest mit Fish S2 Pro). Betraege, Daten, Einheiten und Bindestrich-Nummern bleiben unberuehrt; 10 Tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* sprechtext.ts — Normalisierung vor der Sprachsynthese.
|
||||
*
|
||||
* Befund 2026-09-06 mit Fish S2 Pro: Betraege ("1.248,50 Euro") und Daten
|
||||
* ("14. August 2026") liest das Modell richtig, eine Postleitzahl dagegen
|
||||
* nicht -- "83646" wird als Zahl gelesen und die Hausnummer davor verschmilzt
|
||||
* damit. Andreas' Entscheidung: Ziffern bleiben Ziffern (uebersetzbar), aber
|
||||
* mit Leerzeichen getrennt, und davor eine Ansage mit Pause:
|
||||
* "Bergstraße 7, 83646 Bad Tölz" -> "Bergstraße 7; Postleitzahl 8 3 6 4 6, Bad Tölz"
|
||||
* Das war Variante 4 von vier gehoerten; die stummen Trenner (Punkt,
|
||||
* Gedankenstrich, Auslassung) trennten schlechter.
|
||||
*
|
||||
* Bewusst eng: nur fuenf Ziffern, denen ein grossgeschriebener Ortsname folgt.
|
||||
* Betraege (Komma/Punkt im Inneren, "Euro" dahinter), Daten und Jahreszahlen
|
||||
* bleiben unberuehrt -- die kann das Modell.
|
||||
*/
|
||||
|
||||
// Ortsname: grossgeschriebenes Wort, das keine Einheit ist ("83646 Euro" ist ein Betrag)
|
||||
const KEIN_ORT = "Euro|EUR|Uhr|Prozent|Stück|Stueck|Meter|Kilometer|Gramm|Kilo|Liter|Personen|Tage|Jahre";
|
||||
const ORT = `(?!(?:${KEIN_ORT})\\b)[A-ZÄÖÜ][\\wäöüß.-]+`;
|
||||
|
||||
/** Postleitzahl vor Ortsname: Ziffern einzeln, mit Ansage und Pause davor. */
|
||||
export function postleitzahlenAussprechen(text: string): string {
|
||||
// vor der PLZ: Textanfang, oder ein Zeichen (kein Punkt/Bindestrich: "2026-83646" ist eine Nummer)
|
||||
// plus Komma/Leerzeichen als Trenner -- so bleibt die Hausnummer "7" ein eigenes Wort.
|
||||
return text.replace(
|
||||
new RegExp(`(^|[^\\s.,-](?:,\\s*|\\s+))(\\d{5})(?=\\s+${ORT})`, "gu"),
|
||||
(_, vor: string, plz: string) => {
|
||||
const ziffern = plz.split("").join(" ");
|
||||
const kern = vor.replace(/[,\s]+$/u, "");
|
||||
if (kern === "") return `Postleitzahl ${ziffern},`;
|
||||
// nach Doppelpunkt reicht die Ansage, sonst Semikolon als Pause zur Hausnummer
|
||||
return kern.endsWith(":") ? `${kern} Postleitzahl ${ziffern},` : `${kern}; Postleitzahl ${ziffern},`;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** Alle Regeln fuer Sprechtext; heute nur die Postleitzahl. */
|
||||
export function sprechtextNormalisieren(text: string): string {
|
||||
return postleitzahlenAussprechen(text);
|
||||
}
|
||||
Reference in New Issue
Block a user