import re # Satzende: . ! ? … gefolgt von Whitespace (oder Stringende beim flush). _SENTENCE_END = re.compile(r"[.!?…]+(?=\s)") class SentenceChunker: """Inkrementelle Satzsegmentierung fuer gestreamte LLM-Token. `feed(delta)` liefert die seit dem letzten Aufruf fertig gewordenen Saetze, `flush()` den verbleibenden Rest (z. B. der letzte Satz ohne abschliessendes Leerzeichen). Damit kann pro Satz schon TTS erzeugt werden, waehrend das LLM noch weiterschreibt. """ def __init__(self): self._buffer = "" def feed(self, text: str) -> list[str]: self._buffer += text sentences: list[str] = [] while True: match = _SENTENCE_END.search(self._buffer) if not match: break end = match.end() sentence = self._buffer[:end].strip() self._buffer = self._buffer[end:] if sentence: sentences.append(sentence) return sentences def flush(self) -> str: rest = self._buffer.strip() self._buffer = "" return rest