diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5777d5a..c571b374f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Updated `LLMTextProcessor` and `TTSService` to normalize text input by - splitting into individual characters before aggregation. This ensures proper - sentence boundary detection when LLMs return multiple sentences in a single - chunk (e.g., Google Gemini). +- Text Aggregation Improvements: + + - Updated `LLMTextProcessor` and `TTSService` to normalize text input by + splitting into individual characters before aggregation. This ensures proper + sentence boundary detection when LLMs return multiple sentences in a single + chunk (e.g., Google Gemini). + - All text aggregators now properly support character-by-character streaming + input. + - Refactored text aggregators to use inheritance: `SkipTagsAggregator` and + `PatternPairAggregator` now inherit from `SimpleTextAggregator`, reusing + its lookahead-based sentence detection logic via + `_check_sentence_with_lookahead()`. - Updated `AICFilter` to use Quail STT as the default model (`AICModelType.QUAIL_STT`). Quail STT is optimized for human-to-machine @@ -58,6 +66,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 voice-ui-kit's conversational panel rending of the LLM output after a function call. +- Fixed a bug in `PatternPairAggregator` where pattern handlers could be called + multiple times for patterns with `MatchAction.KEEP` or `MatchAction.AGGREGATE` + actions. + ## [0.0.96] - 2025-11-26 🦃 "Happy Thanksgiving!" 🦃 ### Added diff --git a/src/pipecat/utils/text/simple_text_aggregator.py b/src/pipecat/utils/text/simple_text_aggregator.py index 14e776502..c3bdb99df 100644 --- a/src/pipecat/utils/text/simple_text_aggregator.py +++ b/src/pipecat/utils/text/simple_text_aggregator.py @@ -60,13 +60,19 @@ class SimpleTextAggregator(BaseTextAggregator): # Add new text to buffer self._text += text - # Delegate to sentence detection logic return await self._check_sentence_with_lookahead(text) async def _check_sentence_with_lookahead(self, text: str) -> Optional[Aggregation]: """Check for sentence boundaries using lookahead logic. This method implements the core sentence detection logic with lookahead. + When sentence-ending punctuation is detected, it waits for the next + non-whitespace character before calling NLTK. This disambiguates cases + like "$29." (not a sentence) vs "$29. Next" (sentence ends at period). + Whitespace alone is not meaningful lookahead since it appears in both + cases. Instead, the first non-whitespace character after the punctuation + is used to confirm the sentence boundary. + Subclasses can call this via super() to reuse the lookahead behavior while adding their own logic (e.g., tag handling, pattern matching).