Skip to content

Conversation

@markbackman
Copy link
Contributor

@markbackman markbackman commented Nov 14, 2025

Please describe the changes in your PR. If it is addressing an issue, please reference that as well.

The motivation for this change was discovering that Google Gemini outputs long chunks, sometimes containing multiple sentences. The SimpleTextAggregator extracts only the first sentence and buffers the remainder of the text. When the LLMFullResponseEndFrame is received, all remaining buffered text was being pushed to TTS as one large chunk. This results in potentially many sentences being sent to TTS at once.

The issue is that interruptions capture the last complete sentence; for long outputs with many buffered sentences, it was possible to have many sentences missed during interruption, which could cause the bot to repeat itself or continue speaking after being interrupted.

This PR adds a flush_next_sentence() method to the SimpleTextAggregator which is used when the LLMFullResponseEndFrame is received. Instead of sending all remaining text as one chunk, the buffered sentences are now flushed individually, providing better interruption points throughout the response.

DON'T MERGE YET. WAIT UNTIL #2899 LANDS.

@markbackman markbackman changed the title Improve SimpleTextAggregator to handle multi-sentence chunks Improve TTSService handling of long LLM token outputs Nov 14, 2025
@markbackman
Copy link
Contributor Author

@mattieruth including you since you're working in this area of code. I don't think this impacts your PR but sharing in case it does.

@codecov
Copy link

codecov bot commented Nov 14, 2025

Codecov Report

❌ Patch coverage is 82.35294% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pipecat/services/tts_service.py 57.14% 3 Missing ⚠️
Files with missing lines Coverage Δ
src/pipecat/utils/text/simple_text_aggregator.py 96.00% <100.00%> (+0.76%) ⬆️
src/pipecat/services/tts_service.py 43.40% <57.14%> (-0.31%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.


return None

async def aggregate(self, text: str) -> Optional[str]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if this could be considered a breaking change for anyone using it. We’re keeping the API the same but changing the behavior, and now, to extract the full text, they would need to use it together with flush_next_sentence.

So I am not sure if it would be better if we introduce a new method instead. What do you think ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this changes any functionality. aggregate() works consistently between versions, I think.

Previously, it would:

  • Return either None if no sentences found or the first sentence if an end of sentence is found. The same is true today. It also uses the same logic.

I extracted the logic to avoid duplication. Otherwise, it could have remaining as is without change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think you’re right. Somehow I got confused the first time I looked, but it makes sense now.

And in both versions we would still need to get any remaining text using self._text_aggregator.text at the end.

Cool, makes sense

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly.

Because of Mattie's bot output work, I'm going to have to hold off on merging this. We can stitch in this change once she wraps her work up. Thanks for confirming the approach 🙏

@markbackman markbackman force-pushed the mb/impmrove-simple-text-aggregator branch from 34929b9 to 40ed9a7 Compare November 18, 2025 16:35
Copy link
Contributor

@filipi87 filipi87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement. 🚀🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants