frames: StartInterruptionFrame is deprecated, use InterruptionFrame

This commit is contained in:
Aleix Conchillo Flaqué
2025-09-08 19:07:25 -07:00
parent e27b23694d
commit 9d9f10ae0e
42 changed files with 135 additions and 108 deletions

View File

@@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated ### Deprecated
- `StartInterruptionFrame` is now deprected, use `InterruptionFrame` instead.
- Deprecate `VisionImageFrameAggregator` because `VisionImageRawFrame` has been - Deprecate `VisionImageFrameAggregator` because `VisionImageRawFrame` has been
removed. See the `12*` examples for the new recommended replacement pattern. removed. See the `12*` examples for the new recommended replacement pattern.

View File

@@ -12,8 +12,8 @@ from dotenv import load_dotenv
from loguru import logger from loguru import logger
from pipecat.frames.frames import ( from pipecat.frames.frames import (
InterruptionFrame,
LLMRunFrame, LLMRunFrame,
StartInterruptionFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
UserStoppedSpeakingFrame, UserStoppedSpeakingFrame,
) )
@@ -97,7 +97,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@stt.event_handler("on_speech_started") @stt.event_handler("on_speech_started")
async def on_speech_started(stt, *args, **kwargs): async def on_speech_started(stt, *args, **kwargs):
await task.queue_frames([StartInterruptionFrame(), UserStartedSpeakingFrame()]) await task.queue_frames([InterruptionFrame(), UserStartedSpeakingFrame()])
@stt.event_handler("on_utterance_end") @stt.event_handler("on_utterance_end")
async def on_utterance_end(stt, *args, **kwargs): async def on_utterance_end(stt, *args, **kwargs):

View File

@@ -16,10 +16,10 @@ from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import ( from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMRunFrame, LLMRunFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
@@ -181,9 +181,7 @@ class TranscriptionContextFixup(FrameProcessor):
if isinstance(frame, MagicDemoTranscriptionFrame): if isinstance(frame, MagicDemoTranscriptionFrame):
self._transcript = frame.text self._transcript = frame.text
elif isinstance(frame, LLMFullResponseEndFrame) or isinstance( elif isinstance(frame, LLMFullResponseEndFrame) or isinstance(frame, InterruptionFrame):
frame, StartInterruptionFrame
):
self.swap_user_audio() self.swap_user_audio()
self.add_transcript_back_to_inference_output() self.add_transcript_back_to_inference_output()
self._transcript = "" self._transcript = ""

View File

@@ -18,9 +18,9 @@ from pipecat.frames.frames import (
Frame, Frame,
FunctionCallInProgressFrame, FunctionCallInProgressFrame,
FunctionCallResultFrame, FunctionCallResultFrame,
InterruptionFrame,
LLMRunFrame, LLMRunFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
SystemFrame, SystemFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
@@ -144,7 +144,7 @@ class OutputGate(FrameProcessor):
await self._start() await self._start()
if isinstance(frame, (EndFrame, CancelFrame)): if isinstance(frame, (EndFrame, CancelFrame)):
await self._stop() await self._stop()
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
self._frames_buffer = [] self._frames_buffer = []
self.close_gate() self.close_gate()
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
@@ -232,7 +232,7 @@ class TurnDetectionLLM(Pipeline):
async def pass_only_llm_trigger_frames(frame): async def pass_only_llm_trigger_frames(frame):
return ( return (
isinstance(frame, OpenAILLMContextFrame) isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, StartInterruptionFrame) or isinstance(frame, InterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame) or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame) or isinstance(frame, FunctionCallResultFrame)
) )

View File

@@ -18,9 +18,9 @@ from pipecat.frames.frames import (
Frame, Frame,
FunctionCallInProgressFrame, FunctionCallInProgressFrame,
FunctionCallResultFrame, FunctionCallResultFrame,
InterruptionFrame,
LLMRunFrame, LLMRunFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
SystemFrame, SystemFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
@@ -347,7 +347,7 @@ class OutputGate(FrameProcessor):
await self._start() await self._start()
if isinstance(frame, (EndFrame, CancelFrame)): if isinstance(frame, (EndFrame, CancelFrame)):
await self._stop() await self._stop()
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
self._frames_buffer = [] self._frames_buffer = []
self.close_gate() self.close_gate()
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
@@ -426,7 +426,7 @@ class TurnDetectionLLM(Pipeline):
async def pass_only_llm_trigger_frames(frame): async def pass_only_llm_trigger_frames(frame):
return ( return (
isinstance(frame, OpenAILLMContextFrame) isinstance(frame, OpenAILLMContextFrame)
or isinstance(frame, StartInterruptionFrame) or isinstance(frame, InterruptionFrame)
or isinstance(frame, FunctionCallInProgressFrame) or isinstance(frame, FunctionCallInProgressFrame)
or isinstance(frame, FunctionCallResultFrame) or isinstance(frame, FunctionCallResultFrame)
) )

View File

@@ -20,10 +20,10 @@ from pipecat.frames.frames import (
FunctionCallInProgressFrame, FunctionCallInProgressFrame,
FunctionCallResultFrame, FunctionCallResultFrame,
InputAudioRawFrame, InputAudioRawFrame,
InterruptionFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMRunFrame, LLMRunFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
SystemFrame, SystemFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
@@ -570,7 +570,7 @@ class OutputGate(FrameProcessor):
await self._start() await self._start()
if isinstance(frame, (EndFrame, CancelFrame)): if isinstance(frame, (EndFrame, CancelFrame)):
await self._stop() await self._stop()
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
self._frames_buffer = [] self._frames_buffer = []
self.close_gate() self.close_gate()
await self.push_frame(frame, direction) await self.push_frame(frame, direction)

View File

@@ -15,8 +15,8 @@ from pipecat.frames.frames import (
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
BotStoppedSpeakingFrame, BotStoppedSpeakingFrame,
EndFrame, EndFrame,
InterruptionFrame,
LLMRunFrame, LLMRunFrame,
StartInterruptionFrame,
TTSTextFrame, TTSTextFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
) )
@@ -69,7 +69,7 @@ class CustomObserver(BaseObserver):
# Create direction arrow # Create direction arrow
arrow = "" if direction == FrameDirection.DOWNSTREAM else "" arrow = "" if direction == FrameDirection.DOWNSTREAM else ""
if isinstance(frame, StartInterruptionFrame) and isinstance(src, BaseOutputTransport): if isinstance(frame, InterruptionFrame) and isinstance(src, BaseOutputTransport):
logger.info(f"⚡ INTERRUPTION START: {src} {arrow} {dst} at {time_sec:.2f}s") logger.info(f"⚡ INTERRUPTION START: {src} {arrow} {dst} at {time_sec:.2f}s")
elif isinstance(frame, BotStartedSpeakingFrame): elif isinstance(frame, BotStartedSpeakingFrame):
logger.info(f"🤖 BOT START SPEAKING: {src} {arrow} {dst} at {time_sec:.2f}s") logger.info(f"🤖 BOT START SPEAKING: {src} {arrow} {dst} at {time_sec:.2f}s")

View File

@@ -820,7 +820,7 @@ class FrameProcessorResumeUrgentFrame(SystemFrame):
@dataclass @dataclass
class StartInterruptionFrame(SystemFrame): class InterruptionFrame(SystemFrame):
"""Frame indicating user started speaking (interruption detected). """Frame indicating user started speaking (interruption detected).
Emitted by the BaseInputTransport to indicate that a user has started Emitted by the BaseInputTransport to indicate that a user has started
@@ -832,6 +832,34 @@ class StartInterruptionFrame(SystemFrame):
pass pass
@dataclass
class StartInterruptionFrame(InterruptionFrame):
"""Frame indicating user started speaking (interruption detected).
.. deprecated:: 0.0.85
This frame is deprecated and will be removed in a future version.
Instead, use `InterruptionFrame`.
Emitted by the BaseInputTransport to indicate that a user has started
speaking (i.e. is interrupting). This is similar to
UserStartedSpeakingFrame except that it should be pushed concurrently
with other frames (so the order is not guaranteed).
"""
def __post_init__(self):
super().__post_init__()
import warnings
with warnings.catch_warnings():
warnings.simplefilter("always")
warnings.warn(
"StartInterruptionFrame is deprecated and will be removed in a future version. "
"Instead, use InterruptionFrame.",
DeprecationWarning,
stacklevel=2,
)
@dataclass @dataclass
class UserStartedSpeakingFrame(SystemFrame): class UserStartedSpeakingFrame(SystemFrame):
"""Frame indicating user has started speaking. """Frame indicating user has started speaking.

View File

@@ -36,6 +36,7 @@ from pipecat.frames.frames import (
FunctionCallsStartedFrame, FunctionCallsStartedFrame,
InputAudioRawFrame, InputAudioRawFrame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMMessagesAppendFrame, LLMMessagesAppendFrame,
@@ -48,7 +49,6 @@ from pipecat.frames.frames import (
OpenAILLMContextAssistantTimestampFrame, OpenAILLMContextAssistantTimestampFrame,
SpeechControlParamsFrame, SpeechControlParamsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
UserImageRawFrame, UserImageRawFrame,
@@ -138,7 +138,7 @@ class LLMFullResponseAggregator(FrameProcessor):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._call_event_handler("on_completion", self._aggregation, False) await self._call_event_handler("on_completion", self._aggregation, False)
self._aggregation = "" self._aggregation = ""
self._started = False self._started = False
@@ -838,7 +838,7 @@ class LLMAssistantContextAggregator(LLMContextResponseAggregator):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._handle_interruptions(frame) await self._handle_interruptions(frame)
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, LLMFullResponseStartFrame): elif isinstance(frame, LLMFullResponseStartFrame):
@@ -904,7 +904,7 @@ class LLMAssistantContextAggregator(LLMContextResponseAggregator):
if frame.run_llm: if frame.run_llm:
await self.push_context_frame(FrameDirection.UPSTREAM) await self.push_context_frame(FrameDirection.UPSTREAM)
async def _handle_interruptions(self, frame: StartInterruptionFrame): async def _handle_interruptions(self, frame: InterruptionFrame):
await self.push_aggregation() await self.push_aggregation()
self._started = 0 self._started = 0
await self.reset() await self.reset()

View File

@@ -37,6 +37,7 @@ from pipecat.frames.frames import (
FunctionCallsStartedFrame, FunctionCallsStartedFrame,
InputAudioRawFrame, InputAudioRawFrame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMContextAssistantTimestampFrame, LLMContextAssistantTimestampFrame,
LLMContextFrame, LLMContextFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
@@ -48,7 +49,6 @@ from pipecat.frames.frames import (
LLMSetToolsFrame, LLMSetToolsFrame,
SpeechControlParamsFrame, SpeechControlParamsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
UserImageRawFrame, UserImageRawFrame,
@@ -579,7 +579,7 @@ class LLMAssistantAggregator(LLMContextAggregator):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._handle_interruptions(frame) await self._handle_interruptions(frame)
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, LLMFullResponseStartFrame): elif isinstance(frame, LLMFullResponseStartFrame):
@@ -645,7 +645,7 @@ class LLMAssistantAggregator(LLMContextAggregator):
if frame.run_llm: if frame.run_llm:
await self.push_context_frame(FrameDirection.UPSTREAM) await self.push_context_frame(FrameDirection.UPSTREAM)
async def _handle_interruptions(self, frame: StartInterruptionFrame): async def _handle_interruptions(self, frame: InterruptionFrame):
await self._push_aggregation() await self._push_aggregation()
self._started = 0 self._started = 0
await self.reset() await self.reset()

View File

@@ -25,8 +25,8 @@ from pipecat.frames.frames import (
FunctionCallResultFrame, FunctionCallResultFrame,
InputAudioRawFrame, InputAudioRawFrame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
STTMuteFrame, STTMuteFrame,
TranscriptionFrame, TranscriptionFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
@@ -204,7 +204,7 @@ class STTMuteFilter(FrameProcessor):
if isinstance( if isinstance(
frame, frame,
( (
StartInterruptionFrame, InterruptionFrame,
VADUserStartedSpeakingFrame, VADUserStartedSpeakingFrame,
VADUserStoppedSpeakingFrame, VADUserStoppedSpeakingFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,

View File

@@ -28,8 +28,8 @@ from pipecat.frames.frames import (
FrameProcessorPauseUrgentFrame, FrameProcessorPauseUrgentFrame,
FrameProcessorResumeFrame, FrameProcessorResumeFrame,
FrameProcessorResumeUrgentFrame, FrameProcessorResumeUrgentFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
SystemFrame, SystemFrame,
) )
from pipecat.metrics.metrics import LLMTokenUsage, MetricsData from pipecat.metrics.metrics import LLMTokenUsage, MetricsData
@@ -588,7 +588,7 @@ class FrameProcessor(BaseObject):
if isinstance(frame, StartFrame): if isinstance(frame, StartFrame):
await self.__start(frame) await self.__start(frame)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self._start_interruption() await self._start_interruption()
await self.stop_all_metrics() await self.stop_all_metrics()
elif isinstance(frame, CancelFrame): elif isinstance(frame, CancelFrame):

View File

@@ -19,7 +19,7 @@ from pipecat.frames.frames import (
CancelFrame, CancelFrame,
EndFrame, EndFrame,
Frame, Frame,
StartInterruptionFrame, InterruptionFrame,
TranscriptionFrame, TranscriptionFrame,
TranscriptionMessage, TranscriptionMessage,
TranscriptionUpdateFrame, TranscriptionUpdateFrame,
@@ -195,7 +195,7 @@ class AssistantTranscriptProcessor(BaseTranscriptProcessor):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, (StartInterruptionFrame, CancelFrame)): if isinstance(frame, (InterruptionFrame, CancelFrame)):
# Push frame first otherwise our emitted transcription update frame # Push frame first otherwise our emitted transcription update frame
# might get cleaned up. # might get cleaned up.
await self.push_frame(frame, direction) await self.push_frame(frame, direction)

View File

@@ -20,8 +20,8 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InputDTMFFrame, InputDTMFFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -98,7 +98,7 @@ class ExotelFrameSerializer(FrameSerializer):
Returns: Returns:
Serialized data as string or bytes, or None if the frame isn't handled. Serialized data as string or bytes, or None if the frame isn't handled.
""" """
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
answer = {"event": "clear", "streamSid": self._stream_sid} answer = {"event": "clear", "streamSid": self._stream_sid}
return json.dumps(answer) return json.dumps(answer)
elif isinstance(frame, AudioRawFrame): elif isinstance(frame, AudioRawFrame):

View File

@@ -22,8 +22,8 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InputDTMFFrame, InputDTMFFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -122,7 +122,7 @@ class PlivoFrameSerializer(FrameSerializer):
self._hangup_attempted = True self._hangup_attempted = True
await self._hang_up_call() await self._hang_up_call()
return None return None
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
answer = {"event": "clearAudio", "streamId": self._stream_id} answer = {"event": "clearAudio", "streamId": self._stream_id}
return json.dumps(answer) return json.dumps(answer)
elif isinstance(frame, AudioRawFrame): elif isinstance(frame, AudioRawFrame):

View File

@@ -29,8 +29,8 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InputDTMFFrame, InputDTMFFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
) )
from pipecat.serializers.base_serializer import FrameSerializer, FrameSerializerType from pipecat.serializers.base_serializer import FrameSerializer, FrameSerializerType
@@ -137,7 +137,7 @@ class TelnyxFrameSerializer(FrameSerializer):
self._hangup_attempted = True self._hangup_attempted = True
await self._hang_up_call() await self._hang_up_call()
return None return None
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
answer = {"event": "clear"} answer = {"event": "clear"}
return json.dumps(answer) return json.dumps(answer)
elif isinstance(frame, AudioRawFrame): elif isinstance(frame, AudioRawFrame):

View File

@@ -22,8 +22,8 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InputDTMFFrame, InputDTMFFrame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -122,7 +122,7 @@ class TwilioFrameSerializer(FrameSerializer):
self._hangup_attempted = True self._hangup_attempted = True
await self._hang_up_call() await self._hang_up_call()
return None return None
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
answer = {"event": "clear", "streamSid": self._stream_sid} answer = {"event": "clear", "streamSid": self._stream_sid}
return json.dumps(answer) return json.dumps(answer)
elif isinstance(frame, AudioRawFrame): elif isinstance(frame, AudioRawFrame):

View File

@@ -20,8 +20,8 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -275,7 +275,7 @@ class AsyncAITTSService(InterruptibleTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._started = False
async def _receive_messages(self): async def _receive_messages(self):

View File

@@ -21,13 +21,13 @@ from pipecat.frames.frames import (
DataFrame, DataFrame,
Frame, Frame,
FunctionCallResultFrame, FunctionCallResultFrame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMMessagesAppendFrame, LLMMessagesAppendFrame,
LLMMessagesUpdateFrame, LLMMessagesUpdateFrame,
LLMSetToolChoiceFrame, LLMSetToolChoiceFrame,
LLMSetToolsFrame, LLMSetToolsFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
UserImageRawFrame, UserImageRawFrame,
) )
@@ -306,7 +306,7 @@ class AWSNovaSonicAssistantContextAggregator(OpenAIAssistantContextAggregator):
if isinstance( if isinstance(
frame, frame,
( (
StartInterruptionFrame, InterruptionFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
TextFrame, TextFrame,

View File

@@ -20,8 +20,8 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -371,7 +371,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
return self._websocket return self._websocket
raise Exception("Websocket not connected") raise Exception("Websocket not connected")
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
await self.stop_all_metrics() await self.stop_all_metrics()
if self._context_id: if self._context_id:

View File

@@ -25,9 +25,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -460,7 +460,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._started = False
if isinstance(frame, TTSStoppedFrame): if isinstance(frame, TTSStoppedFrame):
await self.add_word_timestamps([("Reset", 0)]) await self.add_word_timestamps([("Reset", 0)])
@@ -549,7 +549,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
return self._websocket return self._websocket
raise Exception("Websocket not connected") raise Exception("Websocket not connected")
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
"""Handle interruption by closing the current context.""" """Handle interruption by closing the current context."""
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
@@ -856,7 +856,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (StartInterruptionFrame, TTSStoppedFrame)): if isinstance(frame, (InterruptionFrame, TTSStoppedFrame)):
# Reset timing on interruption or stop # Reset timing on interruption or stop
self._reset_state() self._reset_state()

View File

@@ -21,8 +21,8 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -259,7 +259,7 @@ class FishAudioTTSService(InterruptibleTTSService):
return self._websocket return self._websocket
raise Exception("Websocket not connected") raise Exception("Websocket not connected")
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
await self.stop_all_metrics() await self.stop_all_metrics()
self._request_id = None self._request_id = None

View File

@@ -33,6 +33,7 @@ from pipecat.frames.frames import (
InputAudioRawFrame, InputAudioRawFrame,
InputImageRawFrame, InputImageRawFrame,
InputTextRawFrame, InputTextRawFrame,
InterruptionFrame,
LLMContextFrame, LLMContextFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
@@ -41,7 +42,6 @@ from pipecat.frames.frames import (
LLMTextFrame, LLMTextFrame,
LLMUpdateSettingsFrame, LLMUpdateSettingsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TranscriptionFrame, TranscriptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
@@ -752,7 +752,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
elif isinstance(frame, InputImageRawFrame): elif isinstance(frame, InputImageRawFrame):
await self._send_user_video(frame) await self._send_user_video(frame)
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self._handle_interruption() await self._handle_interruption()
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, UserStartedSpeakingFrame): elif isinstance(frame, UserStartedSpeakingFrame):

View File

@@ -36,12 +36,12 @@ from pipecat.frames.frames import (
FunctionCallResultFrame, FunctionCallResultFrame,
FunctionCallResultProperties, FunctionCallResultProperties,
FunctionCallsStartedFrame, FunctionCallsStartedFrame,
InterruptionFrame,
LLMConfigureOutputFrame, LLMConfigureOutputFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMTextFrame, LLMTextFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
UserImageRequestFrame, UserImageRequestFrame,
) )
from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.llm_context import LLMContext
@@ -269,7 +269,7 @@ class LLMService(AIService):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._handle_interruptions(frame) await self._handle_interruptions(frame)
elif isinstance(frame, LLMConfigureOutputFrame): elif isinstance(frame, LLMConfigureOutputFrame):
self._skip_tts = frame.skip_tts self._skip_tts = frame.skip_tts
@@ -286,7 +286,7 @@ class LLMService(AIService):
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
async def _handle_interruptions(self, _: StartInterruptionFrame): async def _handle_interruptions(self, _: InterruptionFrame):
for function_name, entry in self._functions.items(): for function_name, entry in self._functions.items():
if entry.cancel_on_interruption: if entry.cancel_on_interruption:
await self._cancel_function_call(function_name) await self._cancel_function_call(function_name)

View File

@@ -16,8 +16,8 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -180,7 +180,7 @@ class LmntTTSService(InterruptibleTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._started = False
async def _connect(self): async def _connect(self):

View File

@@ -25,9 +25,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSSpeakFrame, TTSSpeakFrame,
TTSStartedFrame, TTSStartedFrame,
@@ -224,7 +224,7 @@ class NeuphonicTTSService(InterruptibleTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._started = False
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):

View File

@@ -23,6 +23,7 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMContextFrame, LLMContextFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
@@ -31,7 +32,6 @@ from pipecat.frames.frames import (
LLMTextFrame, LLMTextFrame,
LLMUpdateSettingsFrame, LLMUpdateSettingsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TranscriptionFrame, TranscriptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
@@ -366,7 +366,7 @@ class OpenAIRealtimeLLMService(LLMService):
elif isinstance(frame, InputAudioRawFrame): elif isinstance(frame, InputAudioRawFrame):
if not self._audio_input_paused: if not self._audio_input_paused:
await self._send_user_audio(frame) await self._send_user_audio(frame)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self._handle_interruption() await self._handle_interruption()
elif isinstance(frame, UserStartedSpeakingFrame): elif isinstance(frame, UserStartedSpeakingFrame):
await self._handle_user_started_speaking(frame) await self._handle_user_started_speaking(frame)
@@ -717,7 +717,7 @@ class OpenAIRealtimeLLMService(LLMService):
async def _handle_evt_speech_started(self, evt): async def _handle_evt_speech_started(self, evt):
await self._truncate_current_audio_response() await self._truncate_current_audio_response()
await self._start_interruption() # cancels this processor task await self._start_interruption() # cancels this processor task
await self.push_frame(StartInterruptionFrame()) # cancels downstream tasks await self.push_frame(InterruptionFrame()) # cancels downstream tasks
await self.push_frame(UserStartedSpeakingFrame()) await self.push_frame(UserStartedSpeakingFrame())
async def _handle_evt_speech_stopped(self, evt): async def _handle_evt_speech_stopped(self, evt):

View File

@@ -24,6 +24,7 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMContextFrame, LLMContextFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
@@ -32,7 +33,6 @@ from pipecat.frames.frames import (
LLMTextFrame, LLMTextFrame,
LLMUpdateSettingsFrame, LLMUpdateSettingsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TranscriptionFrame, TranscriptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
@@ -364,7 +364,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
elif isinstance(frame, InputAudioRawFrame): elif isinstance(frame, InputAudioRawFrame):
if not self._audio_input_paused: if not self._audio_input_paused:
await self._send_user_audio(frame) await self._send_user_audio(frame)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self._handle_interruption() await self._handle_interruption()
elif isinstance(frame, UserStartedSpeakingFrame): elif isinstance(frame, UserStartedSpeakingFrame):
await self._handle_user_started_speaking(frame) await self._handle_user_started_speaking(frame)
@@ -659,7 +659,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
async def _handle_evt_speech_started(self, evt): async def _handle_evt_speech_started(self, evt):
await self._truncate_current_audio_response() await self._truncate_current_audio_response()
await self._start_interruption() # cancels this processor task await self._start_interruption() # cancels this processor task
await self.push_frame(StartInterruptionFrame()) # cancels downstream tasks await self.push_frame(InterruptionFrame()) # cancels downstream tasks
await self.push_frame(UserStartedSpeakingFrame()) await self.push_frame(UserStartedSpeakingFrame())
async def _handle_evt_speech_stopped(self, evt): async def _handle_evt_speech_stopped(self, evt):

View File

@@ -25,8 +25,8 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -312,7 +312,7 @@ class PlayHTTTSService(InterruptibleTTSService):
return self._websocket return self._websocket
raise Exception("Websocket not connected") raise Exception("Websocket not connected")
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
"""Handle interruption by stopping metrics and clearing request ID.""" """Handle interruption by stopping metrics and clearing request ID."""
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
await self.stop_all_metrics() await self.stop_all_metrics()

View File

@@ -24,15 +24,14 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
) )
from pipecat.processors.frame_processor import FrameDirection from pipecat.processors.frame_processor import FrameDirection
from pipecat.services.tts_service import AudioContextWordTTSService, TTSService from pipecat.services.tts_service import AudioContextWordTTSService, TTSService
from pipecat.transcriptions import language
from pipecat.transcriptions.language import Language from pipecat.transcriptions.language import Language
from pipecat.utils.text.base_text_aggregator import BaseTextAggregator from pipecat.utils.text.base_text_aggregator import BaseTextAggregator
from pipecat.utils.text.skip_tags_aggregator import SkipTagsAggregator from pipecat.utils.text.skip_tags_aggregator import SkipTagsAggregator
@@ -280,7 +279,7 @@ class RimeTTSService(AudioContextWordTTSService):
return self._websocket return self._websocket
raise Exception("Websocket not connected") raise Exception("Websocket not connected")
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
"""Handle interruption by clearing current context.""" """Handle interruption by clearing current context."""
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
await self.stop_all_metrics() await self.stop_all_metrics()
@@ -375,7 +374,7 @@ class RimeTTSService(AudioContextWordTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
if isinstance(frame, TTSStoppedFrame): if isinstance(frame, TTSStoppedFrame):
await self.add_word_timestamps([("Reset", 0)]) await self.add_word_timestamps([("Reset", 0)])

View File

@@ -20,9 +20,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
ErrorFrame, ErrorFrame,
Frame, Frame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
TTSStoppedFrame, TTSStoppedFrame,
@@ -455,7 +455,7 @@ class SarvamTTSService(InterruptibleTTSService):
direction: The direction to push the frame. direction: The direction to push the frame.
""" """
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): if isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
self._started = False self._started = False
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):

View File

@@ -15,8 +15,8 @@ from pipecat.frames.frames import (
CancelFrame, CancelFrame,
EndFrame, EndFrame,
Frame, Frame,
InterruptionFrame,
OutputImageRawFrame, OutputImageRawFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStoppedFrame, TTSStoppedFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
@@ -179,7 +179,7 @@ class SimliVideoService(FrameProcessor):
return return
elif isinstance(frame, (EndFrame, CancelFrame)): elif isinstance(frame, (EndFrame, CancelFrame)):
await self._stop() await self._stop()
elif isinstance(frame, (StartInterruptionFrame, UserStartedSpeakingFrame)): elif isinstance(frame, (InterruptionFrame, UserStartedSpeakingFrame)):
if not self._previously_interrupted: if not self._previously_interrupted:
await self._simli_client.clearBuffer() await self._simli_client.clearBuffer()
self._previously_interrupted = self._is_trinity_avatar self._previously_interrupted = self._is_trinity_avatar

View File

@@ -23,12 +23,12 @@ from pipecat.frames.frames import (
CancelFrame, CancelFrame,
EndFrame, EndFrame,
Frame, Frame,
InterruptionFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
OutputImageRawFrame, OutputImageRawFrame,
OutputTransportReadyFrame, OutputTransportReadyFrame,
SpeechOutputAudioRawFrame, SpeechOutputAudioRawFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
TTSStartedFrame, TTSStartedFrame,
) )
@@ -222,7 +222,7 @@ class TavusVideoService(AIService):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._handle_interruptions() await self._handle_interruptions()
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, TTSAudioRawFrame): elif isinstance(frame, TTSAudioRawFrame):

View File

@@ -20,10 +20,10 @@ from pipecat.frames.frames import (
ErrorFrame, ErrorFrame,
Frame, Frame,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
TTSAudioRawFrame, TTSAudioRawFrame,
@@ -309,7 +309,7 @@ class TTSService(AIService):
and not isinstance(frame, TranscriptionFrame) and not isinstance(frame, TranscriptionFrame)
): ):
await self._process_text_frame(frame) await self._process_text_frame(frame)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self._handle_interruption(frame, direction) await self._handle_interruption(frame, direction)
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, (LLMFullResponseEndFrame, EndFrame)): elif isinstance(frame, (LLMFullResponseEndFrame, EndFrame)):
@@ -367,14 +367,14 @@ class TTSService(AIService):
await super().push_frame(frame, direction) await super().push_frame(frame, direction)
if self._push_stop_frames and ( if self._push_stop_frames and (
isinstance(frame, StartInterruptionFrame) isinstance(frame, InterruptionFrame)
or isinstance(frame, TTSStartedFrame) or isinstance(frame, TTSStartedFrame)
or isinstance(frame, TTSAudioRawFrame) or isinstance(frame, TTSAudioRawFrame)
or isinstance(frame, TTSStoppedFrame) or isinstance(frame, TTSStoppedFrame)
): ):
await self._stop_frame_queue.put(frame) await self._stop_frame_queue.put(frame)
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
self._processing_text = False self._processing_text = False
await self._text_aggregator.handle_interruption() await self._text_aggregator.handle_interruption()
for filter in self._text_filters: for filter in self._text_filters:
@@ -438,7 +438,7 @@ class TTSService(AIService):
) )
if isinstance(frame, TTSStartedFrame): if isinstance(frame, TTSStartedFrame):
has_started = True has_started = True
elif isinstance(frame, (TTSStoppedFrame, StartInterruptionFrame)): elif isinstance(frame, (TTSStoppedFrame, InterruptionFrame)):
has_started = False has_started = False
except asyncio.TimeoutError: except asyncio.TimeoutError:
if has_started: if has_started:
@@ -523,7 +523,7 @@ class WordTTSService(TTSService):
elif isinstance(frame, (LLMFullResponseEndFrame, EndFrame)): elif isinstance(frame, (LLMFullResponseEndFrame, EndFrame)):
await self.flush_audio() await self.flush_audio()
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
self._llm_response_started = False self._llm_response_started = False
self.reset_word_timestamps() self.reset_word_timestamps()
@@ -613,7 +613,7 @@ class InterruptibleTTSService(WebsocketTTSService):
# user interrupts we need to reconnect. # user interrupts we need to reconnect.
self._bot_speaking = False self._bot_speaking = False
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
if self._bot_speaking: if self._bot_speaking:
await self._disconnect() await self._disconnect()
@@ -685,7 +685,7 @@ class InterruptibleWordTTSService(WebsocketWordTTSService):
# user interrupts we need to reconnect. # user interrupts we need to reconnect.
self._bot_speaking = False self._bot_speaking = False
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
if self._bot_speaking: if self._bot_speaking:
await self._disconnect() await self._disconnect()
@@ -813,7 +813,7 @@ class AudioContextWordTTSService(WebsocketWordTTSService):
await super().cancel(frame) await super().cancel(frame)
await self._stop_audio_context_task() await self._stop_audio_context_task()
async def _handle_interruption(self, frame: StartInterruptionFrame, direction: FrameDirection): async def _handle_interruption(self, frame: InterruptionFrame, direction: FrameDirection):
await super()._handle_interruption(frame, direction) await super()._handle_interruption(frame, direction)
await self._stop_audio_context_task() await self._stop_audio_context_task()
self._create_audio_context_task() self._create_audio_context_task()

View File

@@ -33,10 +33,10 @@ from pipecat.frames.frames import (
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InputImageRawFrame, InputImageRawFrame,
InterruptionFrame,
MetricsFrame, MetricsFrame,
SpeechControlParamsFrame, SpeechControlParamsFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
StopFrame, StopFrame,
SystemFrame, SystemFrame,
UserSpeakingFrame, UserSpeakingFrame,
@@ -340,7 +340,7 @@ class BaseInputTransport(FrameProcessor):
logger.debug("Bot interruption") logger.debug("Bot interruption")
if self.interruptions_allowed: if self.interruptions_allowed:
await self._start_interruption() await self._start_interruption()
await self.push_frame(StartInterruptionFrame()) await self.push_frame(InterruptionFrame())
async def _handle_user_interruption(self, vad_state: VADState, emulated: bool = False): async def _handle_user_interruption(self, vad_state: VADState, emulated: bool = False):
"""Handle user interruption events based on speaking state.""" """Handle user interruption events based on speaking state."""
@@ -366,7 +366,7 @@ class BaseInputTransport(FrameProcessor):
# Push an out-of-band frame (i.e. not using the ordered push # Push an out-of-band frame (i.e. not using the ordered push
# frame task) to stop everything, specially at the output # frame task) to stop everything, specially at the output
# transport. # transport.
await self.push_frame(StartInterruptionFrame()) await self.push_frame(InterruptionFrame())
elif self.interruption_strategies and self._bot_speaking: elif self.interruption_strategies and self._bot_speaking:
logger.debug( logger.debug(
"User started speaking while bot is speaking with interruption config - " "User started speaking while bot is speaking with interruption config - "

View File

@@ -30,6 +30,7 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
Frame, Frame,
InputTransportMessageUrgentFrame, InputTransportMessageUrgentFrame,
InterruptionFrame,
MixerControlFrame, MixerControlFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
OutputDTMFFrame, OutputDTMFFrame,
@@ -39,7 +40,6 @@ from pipecat.frames.frames import (
SpeechOutputAudioRawFrame, SpeechOutputAudioRawFrame,
SpriteFrame, SpriteFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
SystemFrame, SystemFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
@@ -299,7 +299,7 @@ class BaseOutputTransport(FrameProcessor):
elif isinstance(frame, CancelFrame): elif isinstance(frame, CancelFrame):
await self.cancel(frame) await self.cancel(frame)
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
elif isinstance(frame, StartInterruptionFrame): elif isinstance(frame, InterruptionFrame):
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
await self._handle_frame(frame) await self._handle_frame(frame)
elif isinstance(frame, TransportMessageUrgentFrame) and not isinstance( elif isinstance(frame, TransportMessageUrgentFrame) and not isinstance(
@@ -340,7 +340,7 @@ class BaseOutputTransport(FrameProcessor):
sender = self._media_senders[frame.transport_destination] sender = self._media_senders[frame.transport_destination]
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await sender.handle_interruptions(frame) await sender.handle_interruptions(frame)
elif isinstance(frame, OutputAudioRawFrame): elif isinstance(frame, OutputAudioRawFrame):
await sender.handle_audio_frame(frame) await sender.handle_audio_frame(frame)
@@ -491,7 +491,7 @@ class BaseOutputTransport(FrameProcessor):
await self._cancel_clock_task() await self._cancel_clock_task()
await self._cancel_video_task() await self._cancel_video_task()
async def handle_interruptions(self, _: StartInterruptionFrame): async def handle_interruptions(self, _: InterruptionFrame):
"""Handle interruption events by restarting tasks and clearing buffers. """Handle interruption events by restarting tasks and clearing buffers.
Args: Args:

View File

@@ -25,9 +25,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterruptionFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -618,7 +618,7 @@ class TavusOutputTransport(BaseOutputTransport):
direction: The direction of frame flow in the pipeline. direction: The direction of frame flow in the pipeline.
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._handle_interruptions() await self._handle_interruptions()
async def _handle_interruptions(self): async def _handle_interruptions(self):

View File

@@ -26,9 +26,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterruptionFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -398,7 +398,7 @@ class FastAPIWebsocketOutputTransport(BaseOutputTransport):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._write_frame(frame) await self._write_frame(frame)
self._next_send_time = 0 self._next_send_time = 0

View File

@@ -25,9 +25,9 @@ from pipecat.frames.frames import (
EndFrame, EndFrame,
Frame, Frame,
InputAudioRawFrame, InputAudioRawFrame,
InterruptionFrame,
OutputAudioRawFrame, OutputAudioRawFrame,
StartFrame, StartFrame,
StartInterruptionFrame,
TransportMessageFrame, TransportMessageFrame,
TransportMessageUrgentFrame, TransportMessageUrgentFrame,
) )
@@ -334,7 +334,7 @@ class WebsocketServerOutputTransport(BaseOutputTransport):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, StartInterruptionFrame): if isinstance(frame, InterruptionFrame):
await self._write_frame(frame) await self._write_frame(frame)
self._next_send_time = 0 self._next_send_time = 0

View File

@@ -17,11 +17,11 @@ from pipecat.frames.frames import (
FunctionCallResultFrame, FunctionCallResultFrame,
FunctionCallResultProperties, FunctionCallResultProperties,
InterimTranscriptionFrame, InterimTranscriptionFrame,
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
OpenAILLMContextAssistantTimestampFrame, OpenAILLMContextAssistantTimestampFrame,
SpeechControlParamsFrame, SpeechControlParamsFrame,
StartInterruptionFrame,
TextFrame, TextFrame,
TranscriptionFrame, TranscriptionFrame,
UserStartedSpeakingFrame, UserStartedSpeakingFrame,
@@ -618,7 +618,7 @@ class BaseTestAssistantContextAggreagator:
TextFrame(text="Pipecat."), TextFrame(text="Pipecat."),
LLMFullResponseEndFrame(), LLMFullResponseEndFrame(),
SleepFrame(AGGREGATION_SLEEP), SleepFrame(AGGREGATION_SLEEP),
StartInterruptionFrame(), InterruptionFrame(),
LLMFullResponseStartFrame(), LLMFullResponseStartFrame(),
TextFrame(text="How are "), TextFrame(text="How are "),
TextFrame(text="you?"), TextFrame(text="you?"),
@@ -626,7 +626,7 @@ class BaseTestAssistantContextAggreagator:
] ]
expected_down_frames = [ expected_down_frames = [
*self.EXPECTED_CONTEXT_FRAMES, *self.EXPECTED_CONTEXT_FRAMES,
StartInterruptionFrame, InterruptionFrame,
*self.EXPECTED_CONTEXT_FRAMES, *self.EXPECTED_CONTEXT_FRAMES,
] ]
await run_test( await run_test(

View File

@@ -7,10 +7,10 @@
import unittest import unittest
from pipecat.frames.frames import ( from pipecat.frames.frames import (
InterruptionFrame,
LLMFullResponseEndFrame, LLMFullResponseEndFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMTextFrame, LLMTextFrame,
StartInterruptionFrame,
) )
from pipecat.processors.aggregators.llm_response import LLMFullResponseAggregator from pipecat.processors.aggregators.llm_response import LLMFullResponseAggregator
from pipecat.tests.utils import SleepFrame, run_test from pipecat.tests.utils import SleepFrame, run_test
@@ -113,7 +113,7 @@ class TestLLMFullResponseAggregator(unittest.IsolatedAsyncioTestCase):
LLMFullResponseStartFrame(), LLMFullResponseStartFrame(),
LLMTextFrame("Hello "), LLMTextFrame("Hello "),
SleepFrame(), SleepFrame(),
StartInterruptionFrame(), InterruptionFrame(),
LLMFullResponseStartFrame(), LLMFullResponseStartFrame(),
LLMTextFrame("Hello "), LLMTextFrame("Hello "),
LLMTextFrame("there!"), LLMTextFrame("there!"),
@@ -122,7 +122,7 @@ class TestLLMFullResponseAggregator(unittest.IsolatedAsyncioTestCase):
expected_down_frames = [ expected_down_frames = [
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMTextFrame, LLMTextFrame,
StartInterruptionFrame, InterruptionFrame,
LLMFullResponseStartFrame, LLMFullResponseStartFrame,
LLMTextFrame, LLMTextFrame,
LLMTextFrame, LLMTextFrame,

View File

@@ -14,7 +14,7 @@ from pipecat.frames.frames import (
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
BotStoppedSpeakingFrame, BotStoppedSpeakingFrame,
CancelFrame, CancelFrame,
StartInterruptionFrame, InterruptionFrame,
TranscriptionFrame, TranscriptionFrame,
TranscriptionMessage, TranscriptionMessage,
TranscriptionUpdateFrame, TranscriptionUpdateFrame,
@@ -238,7 +238,7 @@ class TestUserTranscriptProcessor(unittest.IsolatedAsyncioTestCase):
TTSTextFrame(text="Hello"), TTSTextFrame(text="Hello"),
TTSTextFrame(text="world!"), TTSTextFrame(text="world!"),
SleepFrame(), SleepFrame(),
StartInterruptionFrame(), # User interrupts here InterruptionFrame(), # User interrupts here
SleepFrame(), SleepFrame(),
BotStartedSpeakingFrame(), BotStartedSpeakingFrame(),
TTSTextFrame(text="New"), TTSTextFrame(text="New"),
@@ -252,7 +252,7 @@ class TestUserTranscriptProcessor(unittest.IsolatedAsyncioTestCase):
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
TTSTextFrame, # "Hello" TTSTextFrame, # "Hello"
TTSTextFrame, # "world!" TTSTextFrame, # "world!"
StartInterruptionFrame, InterruptionFrame,
TranscriptionUpdateFrame, # First message (emitted due to interruption) TranscriptionUpdateFrame, # First message (emitted due to interruption)
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
TTSTextFrame, # "New" TTSTextFrame, # "New"