From 7850517ba4de2dd70c367b952bcfa7a43af4d78e Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Thu, 12 Feb 2026 08:57:02 -0500 Subject: [PATCH] Fix ElevenLabs TTS word timestamp interleaving across sentences Move cumulative_time and partial word state resets from every run_tts call into the new-context creation block. With the multi-stream WebSocket API, multiple sentences share the same context, so resetting timing state on each run_tts call caused sentences to get overlapping timestamps, resulting in interleaved word ordering. --- src/pipecat/services/elevenlabs/tts.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pipecat/services/elevenlabs/tts.py b/src/pipecat/services/elevenlabs/tts.py index 4dab0c01a..674df691f 100644 --- a/src/pipecat/services/elevenlabs/tts.py +++ b/src/pipecat/services/elevenlabs/tts.py @@ -700,9 +700,6 @@ class ElevenLabsTTSService(AudioContextWordTTSService): try: await self.start_ttfb_metrics() yield TTSStartedFrame(context_id=context_id) - self._cumulative_time = 0 - self._partial_word = "" - self._partial_word_start_time = 0.0 # If a context ID does not exist, use the provided one. # If an ID exists, that means the Pipeline doesn't allow # user interruptions, so continue using the current ID. @@ -710,6 +707,12 @@ class ElevenLabsTTSService(AudioContextWordTTSService): # an interruption, which resets the context ID. if not self._context_id: self._context_id = context_id + # Reset timing state only when starting a new context. + # Within a context, cumulative_time must accumulate across + # sentences so word timestamps are properly sequenced. + self._cumulative_time = 0 + self._partial_word = "" + self._partial_word_start_time = 0.0 if not self.audio_context_available(self._context_id): await self.create_audio_context(self._context_id)