AzureTTSService: Handle first chunk only for timestamps and TTFB metrics

This commit is contained in:
Mark Backman
2026-01-07 16:14:25 -05:00
parent 95f00a3c4b
commit 79a6adbcf3

View File

@@ -283,6 +283,7 @@ class AzureTTSService(WordTTSService, AzureBaseTTSService):
self._word_boundary_queue = asyncio.Queue() self._word_boundary_queue = asyncio.Queue()
self._word_processor_task = None self._word_processor_task = None
self._started = False self._started = False
self._first_chunk = True
self._cumulative_audio_offset: float = 0.0 # Cumulative audio duration in seconds self._cumulative_audio_offset: float = 0.0 # Cumulative audio duration in seconds
async def start(self, frame: StartFrame): async def start(self, frame: StartFrame):
@@ -425,10 +426,16 @@ class AzureTTSService(WordTTSService, AzureBaseTTSService):
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._reset_state()
if isinstance(frame, TTSStoppedFrame): if isinstance(frame, TTSStoppedFrame):
await self.add_word_timestamps([("Reset", 0)]) await self.add_word_timestamps([("Reset", 0)])
def _reset_state(self):
"""Reset TTS state between turns."""
self._started = False
self._first_chunk = True
self._cumulative_audio_offset = 0.0
async def flush_audio(self): async def flush_audio(self):
"""Flush any pending audio data.""" """Flush any pending audio data."""
logger.trace(f"{self}: flushing audio") logger.trace(f"{self}: flushing audio")
@@ -453,8 +460,8 @@ class AzureTTSService(WordTTSService, AzureBaseTTSService):
except Exception as e: except Exception as e:
await self.push_error(error_msg=f"Unknown error occurred: {e}", exception=e) await self.push_error(error_msg=f"Unknown error occurred: {e}", exception=e)
# Reset cumulative audio offset on interruption # Reset state on interruption
self._cumulative_audio_offset = 0.0 self._reset_state()
# Clear the audio queue # Clear the audio queue
while not self._audio_queue.empty(): while not self._audio_queue.empty():
try: try:
@@ -498,19 +505,23 @@ class AzureTTSService(WordTTSService, AzureBaseTTSService):
await self.start_ttfb_metrics() await self.start_ttfb_metrics()
yield TTSStartedFrame() yield TTSStartedFrame()
self._started = True self._started = True
self._first_chunk = True
ssml = self._construct_ssml(text) ssml = self._construct_ssml(text)
self._speech_synthesizer.speak_ssml_async(ssml) self._speech_synthesizer.speak_ssml_async(ssml)
await self.start_tts_usage_metrics(text) await self.start_tts_usage_metrics(text)
# Stream audio chunks as they arrive # Stream audio chunks as they arrive
while True: while True:
chunk = await self._audio_queue.get() chunk = await self._audio_queue.get()
if chunk is None: # End of stream if chunk is None: # End of stream
break break
await self.stop_ttfb_metrics() if self._first_chunk:
await self.start_word_timestamps() await self.stop_ttfb_metrics()
await self.start_word_timestamps()
self._first_chunk = False
frame = TTSAudioRawFrame( frame = TTSAudioRawFrame(
audio=chunk, audio=chunk,
@@ -522,8 +533,7 @@ class AzureTTSService(WordTTSService, AzureBaseTTSService):
except Exception as e: except Exception as e:
yield ErrorFrame(error=f"Unknown error occurred: {e}") yield ErrorFrame(error=f"Unknown error occurred: {e}")
yield TTSStoppedFrame() yield TTSStoppedFrame()
self._started = False self._reset_state()
# Could add reconnection logic here if needed
return return
except Exception as e: except Exception as e: