Merge pull request #4128 from pipecat-ai/mb/end-of-turn-assembly

This commit is contained in:
Mark Backman
2026-03-27 10:47:09 -04:00
committed by GitHub
3 changed files with 19 additions and 5 deletions

1
changelog/4128.added.md Normal file
View File

@@ -0,0 +1 @@
- Added `on_end_of_turn` event handler to `AssemblyAISTTService`. This fires after the final transcript is pushed, providing a reliable hook for end-of-turn logic that doesn't race with `TranscriptionFrame`. Works in both Pipecat and AssemblyAI turn detection modes.

View File

@@ -129,6 +129,16 @@ class AssemblyAISTTService(WebsocketSTTService):
Provides real-time speech transcription using AssemblyAI's WebSocket API. Provides real-time speech transcription using AssemblyAI's WebSocket API.
Supports both interim and final transcriptions with configurable parameters Supports both interim and final transcriptions with configurable parameters
for audio processing and connection management. for audio processing and connection management.
Event handlers available (in addition to WebsocketSTTService events):
- on_end_of_turn(service, transcript): Called when AssemblyAI detects end of turn.
Example::
@service.event_handler("on_end_of_turn")
async def on_end_of_turn(service, transcript):
...
""" """
Settings = AssemblyAISTTSettings Settings = AssemblyAISTTSettings
@@ -303,6 +313,8 @@ class AssemblyAISTTService(WebsocketSTTService):
self._user_speaking = False self._user_speaking = False
self._register_event_handler("on_end_of_turn")
def _configure_pipecat_turn_mode(self, settings: Settings, is_u3_pro: bool): def _configure_pipecat_turn_mode(self, settings: Settings, is_u3_pro: bool):
"""Configure settings for Pipecat turn detection mode. """Configure settings for Pipecat turn detection mode.
@@ -741,6 +753,7 @@ class AssemblyAISTTService(WebsocketSTTService):
) )
await self._trace_transcription(transcript_text, True, language) await self._trace_transcription(transcript_text, True, language)
await self.stop_processing_metrics() await self.stop_processing_metrics()
await self._call_event_handler("on_end_of_turn", transcript_text)
else: else:
await self.push_frame( await self.push_frame(
InterimTranscriptionFrame( InterimTranscriptionFrame(
@@ -774,6 +787,7 @@ class AssemblyAISTTService(WebsocketSTTService):
# above, so ordering is preserved) and upstream. # above, so ordering is preserved) and upstream.
await self.broadcast_frame(UserStoppedSpeakingFrame) await self.broadcast_frame(UserStoppedSpeakingFrame)
self._user_speaking = False self._user_speaking = False
await self._call_event_handler("on_end_of_turn", transcript_text)
else: else:
await self.push_frame( await self.push_frame(
InterimTranscriptionFrame( InterimTranscriptionFrame(

View File

@@ -53,16 +53,15 @@ class DeepgramFluxSTTService(DeepgramFluxSTTBase, WebsocketService):
Event handlers available (in addition to base events): Event handlers available (in addition to base events):
- on_speech_started(service): Deepgram detected start of speech - on_start_of_turn(service, transcript): Deepgram detected start of speech
- on_utterance_end(service): Deepgram detected end of utterance - on_end_of_turn(service, transcript): Deepgram detected end of turn (EOT)
- on_end_of_turn(service): Deepgram detected end of turn (EOT) - on_eager_end_of_turn(service, transcript): Deepgram predicted end of turn (EagerEOT)
- on_eager_end_of_turn(service): Deepgram predicted end of turn (EagerEOT)
- on_turn_resumed(service): User resumed speaking after EagerEOT - on_turn_resumed(service): User resumed speaking after EagerEOT
Example:: Example::
@stt.event_handler("on_end_of_turn") @stt.event_handler("on_end_of_turn")
async def on_end_of_turn(service): async def on_end_of_turn(service, transcript):
... ...
""" """