Smooth Hermes TTS sentence transitions

This commit is contained in:
Mikei386 committed 2026-09-05 15:28:11 +02:00
1 parent cbc312257c
commit 5f3d064bb4
3 files changed
+110 -13

No files matched your search

@@ -132,6 +132,21 @@ class LanguageSegmentationTests(unittest.TestCase):
self.assertIn("5 bis 6 Uhr", spoken)
self.assertIn("Wind maximal 16 Kilometer pro Stunde", spoken)
def test_qwen_speaks_strict_date_ranges_as_calendar_dates(self):
spoken = gateway.prepare_for_qwen_speech(
"Neuigkeiten vom 04.–05.09. und Vergleich 04.09.–06.10.2026."
)
self.assertIn("4. bis 5. September", spoken)
self.assertIn("4. September bis 6. Oktober 2026", spoken)
def test_qwen_does_not_treat_plain_number_ranges_as_dates(self):
spoken = gateway.prepare_for_qwen_speech(
"Version 3.8, Werte 11,3 bis 29,0 und Kontext 80–160K."
)
self.assertIn("Version 3.8", spoken)
self.assertIn("11,3 bis 29,0", spoken)
self.assertIn("80–160K", spoken)
def test_qwen_keeps_prosody_punctuation(self):
spoken = gateway.prepare_for_qwen_speech(
"Ist das gut? Ja! SarahTV: erreichbar."
@@ -224,6 +224,40 @@ def _spoken_date(match: re.Match) -> str:
return result
def _spoken_short_date_range(match: re.Match) -> str:
first_day = int(match.group(1))
last_day = int(match.group(2))
month = int(match.group(3))
year = match.group(4)
month_name = GERMAN_MONTHS.get(month)
if not month_name or not 1 <= first_day <= 31 or not 1 <= last_day <= 31:
return match.group(0)
result = f"{first_day}. bis {last_day}. {month_name}"
if year:
result += f" {year}"
return result
def _spoken_full_date_range(match: re.Match) -> str:
first_day = int(match.group(1))
first_month = int(match.group(2))
last_day = int(match.group(3))
last_month = int(match.group(4))
year = match.group(5)
first_name = GERMAN_MONTHS.get(first_month)
last_name = GERMAN_MONTHS.get(last_month)
if (not first_name or not last_name
or not 1 <= first_day <= 31 or not 1 <= last_day <= 31):
return match.group(0)
if first_month == last_month:
result = f"{first_day}. bis {last_day}. {last_name}"
else:
result = f"{first_day}. {first_name} bis {last_day}. {last_name}"
if year:
result += f" {year}"
return result
def _spell_digits(value: str) -> str:
return " ".join(GERMAN_DIGITS[digit] for digit in value)
@@ -277,6 +311,20 @@ def normalize_for_german_speech(text: str) -> str:
text,
flags=re.IGNORECASE,
)
# Date ranges are deliberately strict: both variants require dotted
# calendar notation, so ordinary numeric ranges remain untouched.
text = re.sub(
r"\b([0-3]?\d)\.([01]?\d)\.\s*[-‐‑‒–—−]\s*"
r"([0-3]?\d)\.([01]?\d)\.(?:(\d{4})\b)?",
_spoken_full_date_range,
text,
)
text = re.sub(
r"\b([0-3]?\d)\.\s*[-‐‑‒–—−]\s*"
r"([0-3]?\d)\.([01]?\d)\.(?:(\d{4})\b)?",
_spoken_short_date_range,
text,
)
text = re.sub(
r"\b([0-3]?\d)\.([01]?\d)\.(?:(\d{4})\b)?",
_spoken_date,