diff --git a/changelog/3583.added.2.md b/changelog/3583.added.2.md new file mode 100644 index 000000000..f0c5c7d1e --- /dev/null +++ b/changelog/3583.added.2.md @@ -0,0 +1 @@ +- Added `VADController` for managing voice activity detection state and emitting speech events independently of transport or pipeline processors. diff --git a/changelog/3583.added.3.md b/changelog/3583.added.3.md new file mode 100644 index 000000000..f5da90407 --- /dev/null +++ b/changelog/3583.added.3.md @@ -0,0 +1 @@ +- Added `VADProcessor` for detecting speech in audio streams within a pipeline. Pushes `VADUserStartedSpeakingFrame`, `VADUserStoppedSpeakingFrame`, and `UserSpeakingFrame` downstream based on VAD state changes. diff --git a/changelog/3583.added.md b/changelog/3583.added.md new file mode 100644 index 000000000..47048e226 --- /dev/null +++ b/changelog/3583.added.md @@ -0,0 +1,10 @@ +- Added `vad_analyzer` parameter to `LLMUserAggregatorParams`. VAD analysis is now handled inside the `LLMUserAggregator` rather than in the transport, keeping voice activity detection closer to where it is consumed. The `vad_analyzer` on `BaseInputTransport` is now deprecated. + + ```python + context_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + vad_analyzer=SileroVADAnalyzer(), + ), + ) + ``` diff --git a/changelog/3583.deprecated.md b/changelog/3583.deprecated.md new file mode 100644 index 000000000..d4ea492eb --- /dev/null +++ b/changelog/3583.deprecated.md @@ -0,0 +1 @@ +- ⚠️ Deprecated `vad_analyzer` parameter on `BaseInputTransport`. Pass `vad_analyzer` to `LLMUserAggregatorParams` instead or use `VADProcessor` in the pipeline. diff --git a/examples/foundational/01-say-one-thing-piper.py b/examples/foundational/01-say-one-thing-piper.py index f6700f886..cace8dbeb 100644 --- a/examples/foundational/01-say-one-thing-piper.py +++ b/examples/foundational/01-say-one-thing-piper.py @@ -24,9 +24,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_out_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_out_enabled=True), diff --git a/examples/foundational/01-say-one-thing-rime.py b/examples/foundational/01-say-one-thing-rime.py index d6b4bad5f..2a31efa68 100644 --- a/examples/foundational/01-say-one-thing-rime.py +++ b/examples/foundational/01-say-one-thing-rime.py @@ -23,9 +23,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_out_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_out_enabled=True), diff --git a/examples/foundational/01-say-one-thing.py b/examples/foundational/01-say-one-thing.py index 4ad179bdb..7df26701c 100644 --- a/examples/foundational/01-say-one-thing.py +++ b/examples/foundational/01-say-one-thing.py @@ -23,9 +23,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_out_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_out_enabled=True), diff --git a/examples/foundational/01c-nvidia-riva-tts.py b/examples/foundational/01c-nvidia-riva-tts.py index 5a42fed19..2be99c5b4 100644 --- a/examples/foundational/01c-nvidia-riva-tts.py +++ b/examples/foundational/01c-nvidia-riva-tts.py @@ -23,9 +23,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_out_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_out_enabled=True), diff --git a/examples/foundational/02-llm-say-one-thing.py b/examples/foundational/02-llm-say-one-thing.py index ef41d271e..f4fbfcbe0 100644 --- a/examples/foundational/02-llm-say-one-thing.py +++ b/examples/foundational/02-llm-say-one-thing.py @@ -25,9 +25,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_out_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_out_enabled=True), diff --git a/examples/foundational/03-still-frame.py b/examples/foundational/03-still-frame.py index 985dcdc9e..def125165 100644 --- a/examples/foundational/03-still-frame.py +++ b/examples/foundational/03-still-frame.py @@ -23,9 +23,8 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( video_out_enabled=True, diff --git a/examples/foundational/03b-still-frame-imagen.py b/examples/foundational/03b-still-frame-imagen.py index 0fa371344..259072959 100644 --- a/examples/foundational/03b-still-frame-imagen.py +++ b/examples/foundational/03b-still-frame-imagen.py @@ -22,9 +22,8 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( video_out_enabled=True, diff --git a/examples/foundational/04-transports-small-webrtc.py b/examples/foundational/04-transports-small-webrtc.py index 8ed1291ba..0ccff0229 100644 --- a/examples/foundational/04-transports-small-webrtc.py +++ b/examples/foundational/04-transports-small-webrtc.py @@ -64,7 +64,6 @@ async def run_example(webrtc_connection: SmallWebRTCConnection): params=TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) @@ -91,6 +90,7 @@ async def run_example(webrtc_connection: SmallWebRTCConnection): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/04a-transports-daily.py b/examples/foundational/04a-transports-daily.py index 27321e028..9a2a9288b 100644 --- a/examples/foundational/04a-transports-daily.py +++ b/examples/foundational/04a-transports-daily.py @@ -49,7 +49,6 @@ async def main(): audio_in_enabled=True, audio_out_enabled=True, transcription_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) @@ -76,6 +75,7 @@ async def main(): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/04b-transports-livekit.py b/examples/foundational/04b-transports-livekit.py index c58e6b5fd..8f100e720 100644 --- a/examples/foundational/04b-transports-livekit.py +++ b/examples/foundational/04b-transports-livekit.py @@ -54,7 +54,6 @@ async def main(): params=LiveKitParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) @@ -84,6 +83,7 @@ async def main(): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/05-sync-speech-and-image.py b/examples/foundational/05-sync-speech-and-image.py index bc0a35ea3..c1b142670 100644 --- a/examples/foundational/05-sync-speech-and-image.py +++ b/examples/foundational/05-sync-speech-and-image.py @@ -65,9 +65,8 @@ class MonthPrepender(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_out_enabled=True, diff --git a/examples/foundational/06-listen-and-respond.py b/examples/foundational/06-listen-and-respond.py index 95e59b167..b23e85766 100644 --- a/examples/foundational/06-listen-and-respond.py +++ b/examples/foundational/06-listen-and-respond.py @@ -62,24 +62,20 @@ class MetricsLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -112,6 +108,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/06a-image-sync.py b/examples/foundational/06a-image-sync.py index cc4664578..8ff1a6069 100644 --- a/examples/foundational/06a-image-sync.py +++ b/examples/foundational/06a-image-sync.py @@ -77,9 +77,8 @@ class ImageSyncAggregator(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -87,7 +86,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -95,7 +93,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -126,6 +123,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07-interruptible-cartesia-http.py b/examples/foundational/07-interruptible-cartesia-http.py index 2d0a9f6d1..b5a7eb026 100644 --- a/examples/foundational/07-interruptible-cartesia-http.py +++ b/examples/foundational/07-interruptible-cartesia-http.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -83,6 +79,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07-interruptible.py b/examples/foundational/07-interruptible.py index d9bb5a449..a016bdeaf 100644 --- a/examples/foundational/07-interruptible.py +++ b/examples/foundational/07-interruptible.py @@ -34,24 +34,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -82,6 +78,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07a-interruptible-speechmatics-vad.py b/examples/foundational/07a-interruptible-speechmatics-vad.py index 864e9635d..d75ae2b1f 100644 --- a/examples/foundational/07a-interruptible-speechmatics-vad.py +++ b/examples/foundational/07a-interruptible-speechmatics-vad.py @@ -33,9 +33,8 @@ from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/07a-interruptible-speechmatics.py b/examples/foundational/07a-interruptible-speechmatics.py index 78959eccf..ebca5caf6 100644 --- a/examples/foundational/07a-interruptible-speechmatics.py +++ b/examples/foundational/07a-interruptible-speechmatics.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -125,6 +121,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07b-interruptible-langchain.py b/examples/foundational/07b-interruptible-langchain.py index b9b5c6177..af1f3082a 100644 --- a/examples/foundational/07b-interruptible-langchain.py +++ b/examples/foundational/07b-interruptible-langchain.py @@ -50,24 +50,20 @@ def get_session_history(session_id: str) -> BaseChatMessageHistory: return message_store[session_id] -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -109,6 +105,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07c-interruptible-deepgram-flux.py b/examples/foundational/07c-interruptible-deepgram-flux.py index 5a1a63e7e..e51a30c1b 100644 --- a/examples/foundational/07c-interruptible-deepgram-flux.py +++ b/examples/foundational/07c-interruptible-deepgram-flux.py @@ -32,9 +32,8 @@ from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/07c-interruptible-deepgram-http.py b/examples/foundational/07c-interruptible-deepgram-http.py index 190d37280..fe2d5c5d8 100644 --- a/examples/foundational/07c-interruptible-deepgram-http.py +++ b/examples/foundational/07c-interruptible-deepgram-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -89,6 +85,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07c-interruptible-deepgram-sagemaker.py b/examples/foundational/07c-interruptible-deepgram-sagemaker.py index a625c1eea..20edf1693 100644 --- a/examples/foundational/07c-interruptible-deepgram-sagemaker.py +++ b/examples/foundational/07c-interruptible-deepgram-sagemaker.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -92,6 +88,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07c-interruptible-deepgram-vad.py b/examples/foundational/07c-interruptible-deepgram-vad.py index e7dca7701..62fb29dff 100644 --- a/examples/foundational/07c-interruptible-deepgram-vad.py +++ b/examples/foundational/07c-interruptible-deepgram-vad.py @@ -33,9 +33,8 @@ from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/07c-interruptible-deepgram.py b/examples/foundational/07c-interruptible-deepgram.py index 7e81b5a74..f4fa91485 100644 --- a/examples/foundational/07c-interruptible-deepgram.py +++ b/examples/foundational/07c-interruptible-deepgram.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -81,6 +77,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07d-interruptible-elevenlabs-http.py b/examples/foundational/07d-interruptible-elevenlabs-http.py index d289258c1..612527e8d 100644 --- a/examples/foundational/07d-interruptible-elevenlabs-http.py +++ b/examples/foundational/07d-interruptible-elevenlabs-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -93,6 +89,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07d-interruptible-elevenlabs.py b/examples/foundational/07d-interruptible-elevenlabs.py index 4850cd473..103d94d48 100644 --- a/examples/foundational/07d-interruptible-elevenlabs.py +++ b/examples/foundational/07d-interruptible-elevenlabs.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07e-interruptible-playht-http.py b/examples/foundational/07e-interruptible-playht-http.py index 0d731d6e4..c982e45fd 100644 --- a/examples/foundational/07e-interruptible-playht-http.py +++ b/examples/foundational/07e-interruptible-playht-http.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07e-interruptible-playht.py b/examples/foundational/07e-interruptible-playht.py index 598565868..fe3ee0349 100644 --- a/examples/foundational/07e-interruptible-playht.py +++ b/examples/foundational/07e-interruptible-playht.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07f-interruptible-azure-http.py b/examples/foundational/07f-interruptible-azure-http.py index 1fc0a1bba..daec3166d 100644 --- a/examples/foundational/07f-interruptible-azure-http.py +++ b/examples/foundational/07f-interruptible-azure-http.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07f-interruptible-azure.py b/examples/foundational/07f-interruptible-azure.py index 0ff69e44e..b1ea08ee4 100644 --- a/examples/foundational/07f-interruptible-azure.py +++ b/examples/foundational/07f-interruptible-azure.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07g-interruptible-openai.py b/examples/foundational/07g-interruptible-openai.py index 3c588cf11..f2b38c8cf 100644 --- a/examples/foundational/07g-interruptible-openai.py +++ b/examples/foundational/07g-interruptible-openai.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07h-interruptible-openpipe.py b/examples/foundational/07h-interruptible-openpipe.py index 555c4049b..c038800bf 100644 --- a/examples/foundational/07h-interruptible-openpipe.py +++ b/examples/foundational/07h-interruptible-openpipe.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -89,6 +85,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07i-interruptible-xtts.py b/examples/foundational/07i-interruptible-xtts.py index 9d1843177..427fab46c 100644 --- a/examples/foundational/07i-interruptible-xtts.py +++ b/examples/foundational/07i-interruptible-xtts.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -89,6 +85,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07j-interruptible-gladia-vad.py b/examples/foundational/07j-interruptible-gladia-vad.py index 58d094d3b..77cc9e58f 100644 --- a/examples/foundational/07j-interruptible-gladia-vad.py +++ b/examples/foundational/07j-interruptible-gladia-vad.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -88,7 +84,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): context = LLMContext(messages) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, - user_params=LLMUserAggregatorParams(user_turn_strategies=ExternalUserTurnStrategies()), + user_params=LLMUserAggregatorParams( + user_turn_strategies=ExternalUserTurnStrategies(), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), + ), ) pipeline = Pipeline( diff --git a/examples/foundational/07j-interruptible-gladia.py b/examples/foundational/07j-interruptible-gladia.py index 664c19ce1..ee29e11df 100644 --- a/examples/foundational/07j-interruptible-gladia.py +++ b/examples/foundational/07j-interruptible-gladia.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -93,6 +89,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07k-interruptible-lmnt.py b/examples/foundational/07k-interruptible-lmnt.py index e616543a3..4f7547c1f 100644 --- a/examples/foundational/07k-interruptible-lmnt.py +++ b/examples/foundational/07k-interruptible-lmnt.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -80,6 +76,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07l-interruptible-groq.py b/examples/foundational/07l-interruptible-groq.py index c1e7e2d4d..a838766b2 100644 --- a/examples/foundational/07l-interruptible-groq.py +++ b/examples/foundational/07l-interruptible-groq.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -82,6 +78,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07m-interruptible-aws-strands.py b/examples/foundational/07m-interruptible-aws-strands.py index f72e3560c..cc8167661 100644 --- a/examples/foundational/07m-interruptible-aws-strands.py +++ b/examples/foundational/07m-interruptible-aws-strands.py @@ -10,6 +10,7 @@ from loguru import logger from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import LLMMessagesAppendFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner @@ -41,24 +42,20 @@ except ImportError: load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -126,6 +123,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07m-interruptible-aws.py b/examples/foundational/07m-interruptible-aws.py index 0f00e1185..c10a5f33d 100644 --- a/examples/foundational/07m-interruptible-aws.py +++ b/examples/foundational/07m-interruptible-aws.py @@ -33,24 +33,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07n-interruptible-gemini-image.py b/examples/foundational/07n-interruptible-gemini-image.py index f32aebee1..4ae497660 100644 --- a/examples/foundational/07n-interruptible-gemini-image.py +++ b/examples/foundational/07n-interruptible-gemini-image.py @@ -50,9 +50,8 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -60,7 +59,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -68,7 +66,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -107,6 +104,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07n-interruptible-gemini.py b/examples/foundational/07n-interruptible-gemini.py index f9dc0bc3b..2539759c5 100644 --- a/examples/foundational/07n-interruptible-gemini.py +++ b/examples/foundational/07n-interruptible-gemini.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -113,6 +109,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07n-interruptible-google-http.py b/examples/foundational/07n-interruptible-google-http.py index 9c58489a9..88bd56e79 100644 --- a/examples/foundational/07n-interruptible-google-http.py +++ b/examples/foundational/07n-interruptible-google-http.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -96,6 +92,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07n-interruptible-google.py b/examples/foundational/07n-interruptible-google.py index a7ebc9dc3..8f1781ce5 100644 --- a/examples/foundational/07n-interruptible-google.py +++ b/examples/foundational/07n-interruptible-google.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -96,6 +92,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07o-interruptible-assemblyai.py b/examples/foundational/07o-interruptible-assemblyai.py index 9cdaafebb..258825c50 100644 --- a/examples/foundational/07o-interruptible-assemblyai.py +++ b/examples/foundational/07o-interruptible-assemblyai.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07p-interruptible-krisp-viva.py b/examples/foundational/07p-interruptible-krisp-viva.py index fd899f213..d502bdcc4 100644 --- a/examples/foundational/07p-interruptible-krisp-viva.py +++ b/examples/foundational/07p-interruptible-krisp-viva.py @@ -53,26 +53,22 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispVivaFilter(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispVivaFilter(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispVivaFilter(), ), } @@ -101,6 +97,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=KrispVivaTurn())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07p-interruptible-krisp.py b/examples/foundational/07p-interruptible-krisp.py index 8665e270e..02451ece4 100644 --- a/examples/foundational/07p-interruptible-krisp.py +++ b/examples/foundational/07p-interruptible-krisp.py @@ -36,26 +36,22 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispFilter(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispFilter(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), audio_in_filter=KrispFilter(), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07q-interruptible-rime-http.py b/examples/foundational/07q-interruptible-rime-http.py index 1cbe7f01b..bfceb1bb3 100644 --- a/examples/foundational/07q-interruptible-rime-http.py +++ b/examples/foundational/07q-interruptible-rime-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -91,6 +87,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07q-interruptible-rime.py b/examples/foundational/07q-interruptible-rime.py index d54a97d78..5113b2c3c 100644 --- a/examples/foundational/07q-interruptible-rime.py +++ b/examples/foundational/07q-interruptible-rime.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -83,6 +79,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07r-interruptible-nvidia.py b/examples/foundational/07r-interruptible-nvidia.py index 460f6ebfe..dda75256d 100644 --- a/examples/foundational/07r-interruptible-nvidia.py +++ b/examples/foundational/07r-interruptible-nvidia.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -82,6 +78,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07s-interruptible-google-audio-in.py b/examples/foundational/07s-interruptible-google-audio-in.py index 9aaa3c415..54c0da1b9 100644 --- a/examples/foundational/07s-interruptible-google-audio-in.py +++ b/examples/foundational/07s-interruptible-google-audio-in.py @@ -197,24 +197,20 @@ class TranscriptionContextFixup(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -255,6 +251,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) audio_collector = UserAudioCollector(context, user_aggregator) diff --git a/examples/foundational/07t-interruptible-fish.py b/examples/foundational/07t-interruptible-fish.py index 86750b631..5a7c368f1 100644 --- a/examples/foundational/07t-interruptible-fish.py +++ b/examples/foundational/07t-interruptible-fish.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07v-interruptible-neuphonic-http.py b/examples/foundational/07v-interruptible-neuphonic-http.py index 5f5928cad..3c82608bc 100644 --- a/examples/foundational/07v-interruptible-neuphonic-http.py +++ b/examples/foundational/07v-interruptible-neuphonic-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07v-interruptible-neuphonic.py b/examples/foundational/07v-interruptible-neuphonic.py index 78fc9c2e8..fd0c3361c 100644 --- a/examples/foundational/07v-interruptible-neuphonic.py +++ b/examples/foundational/07v-interruptible-neuphonic.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -83,6 +79,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07w-interruptible-fal.py b/examples/foundational/07w-interruptible-fal.py index a60725b16..b6dda13a9 100644 --- a/examples/foundational/07w-interruptible-fal.py +++ b/examples/foundational/07w-interruptible-fal.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07x-interruptible-local.py b/examples/foundational/07x-interruptible-local.py index 0baa6ebad..aeb1b1f32 100644 --- a/examples/foundational/07x-interruptible-local.py +++ b/examples/foundational/07x-interruptible-local.py @@ -41,7 +41,6 @@ async def main(): LocalAudioTransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ) ) @@ -68,6 +67,7 @@ async def main(): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07y-interruptible-minimax.py b/examples/foundational/07y-interruptible-minimax.py index 855e41516..1bd8f716f 100644 --- a/examples/foundational/07y-interruptible-minimax.py +++ b/examples/foundational/07y-interruptible-minimax.py @@ -38,24 +38,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -92,6 +88,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07z-interruptible-sarvam-http.py b/examples/foundational/07z-interruptible-sarvam-http.py index df176ab22..a5b656b1a 100644 --- a/examples/foundational/07z-interruptible-sarvam-http.py +++ b/examples/foundational/07z-interruptible-sarvam-http.py @@ -38,24 +38,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -94,6 +90,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07z-interruptible-sarvam.py b/examples/foundational/07z-interruptible-sarvam.py index 990af6fef..3ead95eb0 100644 --- a/examples/foundational/07z-interruptible-sarvam.py +++ b/examples/foundational/07z-interruptible-sarvam.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07za-interruptible-soniox.py b/examples/foundational/07za-interruptible-soniox.py index 15da33507..5f1a45fe8 100644 --- a/examples/foundational/07za-interruptible-soniox.py +++ b/examples/foundational/07za-interruptible-soniox.py @@ -39,17 +39,14 @@ transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -82,6 +79,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zb-interruptible-inworld-http.py b/examples/foundational/07zb-interruptible-inworld-http.py index c67984f7c..90fb20bd0 100644 --- a/examples/foundational/07zb-interruptible-inworld-http.py +++ b/examples/foundational/07zb-interruptible-inworld-http.py @@ -41,17 +41,14 @@ transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -89,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zb-interruptible-inworld.py b/examples/foundational/07zb-interruptible-inworld.py index 46e07dc5f..9c8fa720b 100644 --- a/examples/foundational/07zb-interruptible-inworld.py +++ b/examples/foundational/07zb-interruptible-inworld.py @@ -41,17 +41,14 @@ transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +81,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zc-interruptible-asyncai-http.py b/examples/foundational/07zc-interruptible-asyncai-http.py index 21da1cf17..dff140ac3 100644 --- a/examples/foundational/07zc-interruptible-asyncai-http.py +++ b/examples/foundational/07zc-interruptible-asyncai-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zc-interruptible-asyncai.py b/examples/foundational/07zc-interruptible-asyncai.py index d3dcf8766..3596f40a1 100644 --- a/examples/foundational/07zc-interruptible-asyncai.py +++ b/examples/foundational/07zc-interruptible-asyncai.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zd-interruptible-aicoustics.py b/examples/foundational/07zd-interruptible-aicoustics.py index ca205fc1d..2a355ba18 100644 --- a/examples/foundational/07zd-interruptible-aicoustics.py +++ b/examples/foundational/07zd-interruptible-aicoustics.py @@ -54,9 +54,8 @@ def _create_aic_filter() -> AICFilter: ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: ( lambda aic: DailyParams( diff --git a/examples/foundational/07ze-interruptible-hume.py b/examples/foundational/07ze-interruptible-hume.py index e9a8e355c..a864032c4 100644 --- a/examples/foundational/07ze-interruptible-hume.py +++ b/examples/foundational/07ze-interruptible-hume.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zf-interruptible-gradium.py b/examples/foundational/07zf-interruptible-gradium.py index e4314ac3a..02f33f41b 100644 --- a/examples/foundational/07zf-interruptible-gradium.py +++ b/examples/foundational/07zf-interruptible-gradium.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zg-interruptible-camb.py b/examples/foundational/07zg-interruptible-camb.py index 256eff6f7..d0312a5f7 100644 --- a/examples/foundational/07zg-interruptible-camb.py +++ b/examples/foundational/07zg-interruptible-camb.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -85,6 +81,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/07zh-interruptible-hathora.py b/examples/foundational/07zh-interruptible-hathora.py index f4bd169b1..c7876217f 100644 --- a/examples/foundational/07zh-interruptible-hathora.py +++ b/examples/foundational/07zh-interruptible-hathora.py @@ -34,24 +34,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -88,6 +84,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/08-custom-frame-processor.py b/examples/foundational/08-custom-frame-processor.py index 82ff858b6..c561c46f3 100644 --- a/examples/foundational/08-custom-frame-processor.py +++ b/examples/foundational/08-custom-frame-processor.py @@ -77,20 +77,17 @@ class MetricsFrameLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -121,6 +118,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/09-mirror.py b/examples/foundational/09-mirror.py index 80b76b3b8..478fe9daf 100644 --- a/examples/foundational/09-mirror.py +++ b/examples/foundational/09-mirror.py @@ -47,9 +47,8 @@ class MirrorProcessor(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/09a-local-mirror.py b/examples/foundational/09a-local-mirror.py index 42d9af41e..217136e58 100644 --- a/examples/foundational/09a-local-mirror.py +++ b/examples/foundational/09a-local-mirror.py @@ -50,9 +50,8 @@ class MirrorProcessor(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/10-wake-phrase.py b/examples/foundational/10-wake-phrase.py index fe7052a5b..f87255814 100644 --- a/examples/foundational/10-wake-phrase.py +++ b/examples/foundational/10-wake-phrase.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -85,6 +81,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/11-sound-effects.py b/examples/foundational/11-sound-effects.py index b517cf447..297db8a45 100644 --- a/examples/foundational/11-sound-effects.py +++ b/examples/foundational/11-sound-effects.py @@ -85,24 +85,20 @@ class InboundSoundEffectWrapper(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -133,6 +129,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) out_sound = OutboundSoundEffectWrapper() diff --git a/examples/foundational/12-describe-image-openai.py b/examples/foundational/12-describe-image-openai.py index 60cdeafed..413573eb7 100644 --- a/examples/foundational/12-describe-image-openai.py +++ b/examples/foundational/12-describe-image-openai.py @@ -36,19 +36,16 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -79,6 +76,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/12a-describe-image-anthropic.py b/examples/foundational/12a-describe-image-anthropic.py index 507cca019..0b611c143 100644 --- a/examples/foundational/12a-describe-image-anthropic.py +++ b/examples/foundational/12a-describe-image-anthropic.py @@ -36,19 +36,16 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -79,6 +76,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/12b-describe-image-aws.py b/examples/foundational/12b-describe-image-aws.py index ed02f5024..4c62a1fbf 100644 --- a/examples/foundational/12b-describe-image-aws.py +++ b/examples/foundational/12b-describe-image-aws.py @@ -36,19 +36,16 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +83,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/12c-describe-image-gemini-flash.py b/examples/foundational/12c-describe-image-gemini-flash.py index a00465135..b1cd3fd73 100644 --- a/examples/foundational/12c-describe-image-gemini-flash.py +++ b/examples/foundational/12c-describe-image-gemini-flash.py @@ -36,19 +36,16 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -79,6 +76,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/12d-describe-image-moondream.py b/examples/foundational/12d-describe-image-moondream.py index 4b9ff0912..070b004a1 100644 --- a/examples/foundational/12d-describe-image-moondream.py +++ b/examples/foundational/12d-describe-image-moondream.py @@ -11,8 +11,6 @@ from dotenv import load_dotenv from loguru import logger from PIL import Image -from pipecat.audio.vad.silero import SileroVADAnalyzer -from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import UserImageRawFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner @@ -27,17 +25,14 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } diff --git a/examples/foundational/13-whisper-transcription.py b/examples/foundational/13-whisper-transcription.py index 79d706a5a..e2f0f61e0 100644 --- a/examples/foundational/13-whisper-transcription.py +++ b/examples/foundational/13-whisper-transcription.py @@ -35,9 +35,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/13b-deepgram-transcription.py b/examples/foundational/13b-deepgram-transcription.py index ce18b3f16..ed83bd1d5 100644 --- a/examples/foundational/13b-deepgram-transcription.py +++ b/examples/foundational/13b-deepgram-transcription.py @@ -35,9 +35,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13c-gladia-transcription.py b/examples/foundational/13c-gladia-transcription.py index 24833fc5d..c98fda727 100644 --- a/examples/foundational/13c-gladia-transcription.py +++ b/examples/foundational/13c-gladia-transcription.py @@ -35,9 +35,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13c-gladia-translation.py b/examples/foundational/13c-gladia-translation.py index 0f69f0649..edc294858 100644 --- a/examples/foundational/13c-gladia-translation.py +++ b/examples/foundational/13c-gladia-translation.py @@ -44,9 +44,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13d-assemblyai-transcription.py b/examples/foundational/13d-assemblyai-transcription.py index a7da1f996..06ea52cd5 100644 --- a/examples/foundational/13d-assemblyai-transcription.py +++ b/examples/foundational/13d-assemblyai-transcription.py @@ -35,9 +35,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13e-whisper-mlx.py b/examples/foundational/13e-whisper-mlx.py index 609ebf5f6..ba90d0850 100644 --- a/examples/foundational/13e-whisper-mlx.py +++ b/examples/foundational/13e-whisper-mlx.py @@ -56,9 +56,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/13f-cartesia-transcription.py b/examples/foundational/13f-cartesia-transcription.py index c8c39629a..d3b83abb0 100644 --- a/examples/foundational/13f-cartesia-transcription.py +++ b/examples/foundational/13f-cartesia-transcription.py @@ -35,9 +35,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13g-sambanova-transcription.py b/examples/foundational/13g-sambanova-transcription.py index bcccf2963..cebeea615 100644 --- a/examples/foundational/13g-sambanova-transcription.py +++ b/examples/foundational/13g-sambanova-transcription.py @@ -57,9 +57,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/13h-speechmatics-transcription.py b/examples/foundational/13h-speechmatics-transcription.py index eb5b4148f..f1d1d93c6 100644 --- a/examples/foundational/13h-speechmatics-transcription.py +++ b/examples/foundational/13h-speechmatics-transcription.py @@ -36,9 +36,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True), "twilio": lambda: FastAPIWebsocketParams(audio_in_enabled=True), diff --git a/examples/foundational/13k-elevenlabs-transcription.py b/examples/foundational/13k-elevenlabs-transcription.py index 2568508f2..f27bbb52a 100644 --- a/examples/foundational/13k-elevenlabs-transcription.py +++ b/examples/foundational/13k-elevenlabs-transcription.py @@ -37,9 +37,8 @@ class TranscriptionLogger(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams(audio_in_enabled=True, vad_analyzer=SileroVADAnalyzer()), "twilio": lambda: FastAPIWebsocketParams( diff --git a/examples/foundational/14-function-calling.py b/examples/foundational/14-function-calling.py index 22f84397c..a1cda33f6 100644 --- a/examples/foundational/14-function-calling.py +++ b/examples/foundational/14-function-calling.py @@ -46,24 +46,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -132,6 +128,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14a-function-calling-anthropic.py b/examples/foundational/14a-function-calling-anthropic.py index 08133cf83..783ea7c7c 100644 --- a/examples/foundational/14a-function-calling-anthropic.py +++ b/examples/foundational/14a-function-calling-anthropic.py @@ -48,24 +48,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -127,6 +123,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14c-function-calling-together.py b/examples/foundational/14c-function-calling-together.py index a4bf5cd19..49f5b98e3 100644 --- a/examples/foundational/14c-function-calling-together.py +++ b/examples/foundational/14c-function-calling-together.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -118,6 +114,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14d-function-calling-anthropic-video.py b/examples/foundational/14d-function-calling-anthropic-video.py index c9dacaa75..971016fdf 100644 --- a/examples/foundational/14d-function-calling-anthropic-video.py +++ b/examples/foundational/14d-function-calling-anthropic-video.py @@ -71,21 +71,18 @@ async def fetch_user_image(params: FunctionCallParams): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -139,6 +136,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14d-function-calling-aws-video.py b/examples/foundational/14d-function-calling-aws-video.py index 9faa925aa..a78500819 100644 --- a/examples/foundational/14d-function-calling-aws-video.py +++ b/examples/foundational/14d-function-calling-aws-video.py @@ -71,21 +71,18 @@ async def fetch_user_image(params: FunctionCallParams): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -146,6 +143,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14d-function-calling-gemini-flash-video.py b/examples/foundational/14d-function-calling-gemini-flash-video.py index 857eb92b6..9470f19ca 100644 --- a/examples/foundational/14d-function-calling-gemini-flash-video.py +++ b/examples/foundational/14d-function-calling-gemini-flash-video.py @@ -71,21 +71,18 @@ async def fetch_user_image(params: FunctionCallParams): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -139,6 +136,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14d-function-calling-moondream-video.py b/examples/foundational/14d-function-calling-moondream-video.py index 3e64d5bd8..263b51215 100644 --- a/examples/foundational/14d-function-calling-moondream-video.py +++ b/examples/foundational/14d-function-calling-moondream-video.py @@ -102,21 +102,18 @@ class MoondreamTextFrameWrapper(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -169,6 +166,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14d-function-calling-openai-video.py b/examples/foundational/14d-function-calling-openai-video.py index ec201cc3a..ea18b0d11 100644 --- a/examples/foundational/14d-function-calling-openai-video.py +++ b/examples/foundational/14d-function-calling-openai-video.py @@ -72,21 +72,18 @@ async def fetch_user_image(params: FunctionCallParams): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -139,6 +136,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14e-function-calling-google.py b/examples/foundational/14e-function-calling-google.py index 56cdd53c1..e8757bb71 100644 --- a/examples/foundational/14e-function-calling-google.py +++ b/examples/foundational/14e-function-calling-google.py @@ -81,21 +81,18 @@ async def get_image(params: FunctionCallParams): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -192,6 +189,7 @@ indicate you should use the get_image tool are: user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14f-function-calling-groq.py b/examples/foundational/14f-function-calling-groq.py index 989dafb0e..ff410cb6e 100644 --- a/examples/foundational/14f-function-calling-groq.py +++ b/examples/foundational/14f-function-calling-groq.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -115,6 +111,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14g-function-calling-grok.py b/examples/foundational/14g-function-calling-grok.py index cfb52cbc5..ba087c2f9 100644 --- a/examples/foundational/14g-function-calling-grok.py +++ b/examples/foundational/14g-function-calling-grok.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -111,6 +107,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14h-function-calling-azure.py b/examples/foundational/14h-function-calling-azure.py index a108a7779..c4036c282 100644 --- a/examples/foundational/14h-function-calling-azure.py +++ b/examples/foundational/14h-function-calling-azure.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -119,6 +115,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14i-function-calling-fireworks.py b/examples/foundational/14i-function-calling-fireworks.py index 9b1692430..61dc21af5 100644 --- a/examples/foundational/14i-function-calling-fireworks.py +++ b/examples/foundational/14i-function-calling-fireworks.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -122,6 +118,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14j-function-calling-nvidia.py b/examples/foundational/14j-function-calling-nvidia.py index 354e0fbdb..52c737d18 100644 --- a/examples/foundational/14j-function-calling-nvidia.py +++ b/examples/foundational/14j-function-calling-nvidia.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -124,6 +120,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14k-function-calling-cerebras.py b/examples/foundational/14k-function-calling-cerebras.py index 994c29169..fc1c821e1 100644 --- a/examples/foundational/14k-function-calling-cerebras.py +++ b/examples/foundational/14k-function-calling-cerebras.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -125,6 +121,7 @@ Start by asking me for my location. Then, use 'get_weather_current' to give me a user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14l-function-calling-deepseek.py b/examples/foundational/14l-function-calling-deepseek.py index fc9dc5677..8be0b93d7 100644 --- a/examples/foundational/14l-function-calling-deepseek.py +++ b/examples/foundational/14l-function-calling-deepseek.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -125,6 +121,7 @@ Start by asking me for my location. Then, use 'get_weather_current' to give me a user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14m-function-calling-openrouter.py b/examples/foundational/14m-function-calling-openrouter.py index 963da638b..eddf7e0e2 100644 --- a/examples/foundational/14m-function-calling-openrouter.py +++ b/examples/foundational/14m-function-calling-openrouter.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -119,6 +115,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14n-function-calling-perplexity.py b/examples/foundational/14n-function-calling-perplexity.py index a3745cc5a..33d12fe88 100644 --- a/examples/foundational/14n-function-calling-perplexity.py +++ b/examples/foundational/14n-function-calling-perplexity.py @@ -41,24 +41,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -89,6 +85,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14o-function-calling-gemini-openai-format.py b/examples/foundational/14o-function-calling-gemini-openai-format.py index 8c6356507..4490d30b0 100644 --- a/examples/foundational/14o-function-calling-gemini-openai-format.py +++ b/examples/foundational/14o-function-calling-gemini-openai-format.py @@ -37,9 +37,8 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/14p-function-calling-gemini-vertex-ai.py b/examples/foundational/14p-function-calling-gemini-vertex-ai.py index 0fe2da06d..e75c288ad 100644 --- a/examples/foundational/14p-function-calling-gemini-vertex-ai.py +++ b/examples/foundational/14p-function-calling-gemini-vertex-ai.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -120,6 +116,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14q-function-calling-qwen.py b/examples/foundational/14q-function-calling-qwen.py index 9b6c641ed..2363c840f 100644 --- a/examples/foundational/14q-function-calling-qwen.py +++ b/examples/foundational/14q-function-calling-qwen.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -117,6 +113,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14r-function-calling-aws.py b/examples/foundational/14r-function-calling-aws.py index ff438ac27..7e144dc9e 100644 --- a/examples/foundational/14r-function-calling-aws.py +++ b/examples/foundational/14r-function-calling-aws.py @@ -45,24 +45,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -132,6 +128,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14s-function-calling-sambanova.py b/examples/foundational/14s-function-calling-sambanova.py index 60076e370..025aa1cc9 100644 --- a/examples/foundational/14s-function-calling-sambanova.py +++ b/examples/foundational/14s-function-calling-sambanova.py @@ -43,24 +43,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -121,6 +117,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14t-function-calling-direct.py b/examples/foundational/14t-function-calling-direct.py index ae6db7564..59e09a76a 100644 --- a/examples/foundational/14t-function-calling-direct.py +++ b/examples/foundational/14t-function-calling-direct.py @@ -59,24 +59,20 @@ async def get_restaurant_recommendation(params: FunctionCallParams, location: st await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -118,6 +114,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14u-function-calling-ollama.py b/examples/foundational/14u-function-calling-ollama.py index a76c65dd8..ed04c2236 100644 --- a/examples/foundational/14u-function-calling-ollama.py +++ b/examples/foundational/14u-function-calling-ollama.py @@ -47,24 +47,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -133,6 +129,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14v-function-calling-openai.py b/examples/foundational/14v-function-calling-openai.py index ac60c0901..7265ce73a 100644 --- a/examples/foundational/14v-function-calling-openai.py +++ b/examples/foundational/14v-function-calling-openai.py @@ -46,24 +46,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -140,6 +136,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14w-function-calling-mistral.py b/examples/foundational/14w-function-calling-mistral.py index 721726f82..03b344df5 100644 --- a/examples/foundational/14w-function-calling-mistral.py +++ b/examples/foundational/14w-function-calling-mistral.py @@ -46,24 +46,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -128,6 +124,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/14x-function-calling-openpipe.py b/examples/foundational/14x-function-calling-openpipe.py index 42c951a4e..7a4a5f2e7 100644 --- a/examples/foundational/14x-function-calling-openpipe.py +++ b/examples/foundational/14x-function-calling-openpipe.py @@ -47,24 +47,20 @@ async def fetch_restaurant_recommendation(params: FunctionCallParams): await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -138,6 +134,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/15-switch-voices.py b/examples/foundational/15-switch-voices.py index ff0a0e9f7..d0684b045 100644 --- a/examples/foundational/15-switch-voices.py +++ b/examples/foundational/15-switch-voices.py @@ -91,24 +91,20 @@ class SwitchVoices(ParallelPipeline): return self.current_voice == "Barbershop Man" -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -150,6 +146,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/15a-switch-languages.py b/examples/foundational/15a-switch-languages.py index 73e818bc5..c92b6b5e5 100644 --- a/examples/foundational/15a-switch-languages.py +++ b/examples/foundational/15a-switch-languages.py @@ -80,24 +80,20 @@ class SwitchLanguage(ParallelPipeline): return self.current_language == "Spanish" -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -140,6 +136,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/16-gpu-container-local-bot.py b/examples/foundational/16-gpu-container-local-bot.py index a64edcec2..84e28259b 100644 --- a/examples/foundational/16-gpu-container-local-bot.py +++ b/examples/foundational/16-gpu-container-local-bot.py @@ -39,24 +39,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -94,6 +90,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/17-detect-user-idle.py b/examples/foundational/17-detect-user-idle.py index 52277a584..a7d7c6f69 100644 --- a/examples/foundational/17-detect-user-idle.py +++ b/examples/foundational/17-detect-user-idle.py @@ -78,24 +78,20 @@ class IdleHandler: await aggregator.push_frame(EndTaskFrame(), FrameDirection.UPSTREAM) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -127,6 +123,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), user_idle_timeout=5.0, # Detect user idle after 5 seconds + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/18-gstreamer-filesrc.py b/examples/foundational/18-gstreamer-filesrc.py index 56631c443..f1c3062b4 100644 --- a/examples/foundational/18-gstreamer-filesrc.py +++ b/examples/foundational/18-gstreamer-filesrc.py @@ -20,9 +20,8 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_out_enabled=True, diff --git a/examples/foundational/18a-gstreamer-videotestsrc.py b/examples/foundational/18a-gstreamer-videotestsrc.py index 3ab5cf8b7..8398f1f7f 100644 --- a/examples/foundational/18a-gstreamer-videotestsrc.py +++ b/examples/foundational/18a-gstreamer-videotestsrc.py @@ -19,9 +19,8 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( video_out_enabled=True, diff --git a/examples/foundational/19-openai-realtime-beta.py b/examples/foundational/19-openai-realtime-beta.py index 37fe86f96..c69d0ca92 100644 --- a/examples/foundational/19-openai-realtime-beta.py +++ b/examples/foundational/19-openai-realtime-beta.py @@ -86,9 +86,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19-openai-realtime.py b/examples/foundational/19-openai-realtime.py index 443a2817b..0d59782f1 100644 --- a/examples/foundational/19-openai-realtime.py +++ b/examples/foundational/19-openai-realtime.py @@ -113,9 +113,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19a-azure-realtime-beta.py b/examples/foundational/19a-azure-realtime-beta.py index d287344cb..d25f53e96 100644 --- a/examples/foundational/19a-azure-realtime-beta.py +++ b/examples/foundational/19a-azure-realtime-beta.py @@ -84,9 +84,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19a-azure-realtime.py b/examples/foundational/19a-azure-realtime.py index 20932da3c..6883a1f09 100644 --- a/examples/foundational/19a-azure-realtime.py +++ b/examples/foundational/19a-azure-realtime.py @@ -87,9 +87,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19b-openai-realtime-beta-text.py b/examples/foundational/19b-openai-realtime-beta-text.py index 4ddd068a6..83e1563a0 100644 --- a/examples/foundational/19b-openai-realtime-beta-text.py +++ b/examples/foundational/19b-openai-realtime-beta-text.py @@ -86,9 +86,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19b-openai-realtime-text.py b/examples/foundational/19b-openai-realtime-text.py index a3190f44c..38731d72a 100644 --- a/examples/foundational/19b-openai-realtime-text.py +++ b/examples/foundational/19b-openai-realtime-text.py @@ -89,9 +89,8 @@ restaurant_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/19c-openai-realtime-live-video.py b/examples/foundational/19c-openai-realtime-live-video.py index 31369717d..3f091f712 100644 --- a/examples/foundational/19c-openai-realtime-live-video.py +++ b/examples/foundational/19c-openai-realtime-live-video.py @@ -39,9 +39,8 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/20a-persistent-context-openai.py b/examples/foundational/20a-persistent-context-openai.py index ae7c6ca8e..a98a7cd36 100644 --- a/examples/foundational/20a-persistent-context-openai.py +++ b/examples/foundational/20a-persistent-context-openai.py @@ -159,24 +159,20 @@ tools = ToolsSchema( ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -207,6 +203,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/20b-persistent-context-openai-realtime-beta.py b/examples/foundational/20b-persistent-context-openai-realtime-beta.py index 19ccf81f7..cb4ffa642 100644 --- a/examples/foundational/20b-persistent-context-openai-realtime-beta.py +++ b/examples/foundational/20b-persistent-context-openai-realtime-beta.py @@ -155,9 +155,8 @@ tools = [ ] -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/20b-persistent-context-openai-realtime.py b/examples/foundational/20b-persistent-context-openai-realtime.py index 0d09cf40a..a24ff39e5 100644 --- a/examples/foundational/20b-persistent-context-openai-realtime.py +++ b/examples/foundational/20b-persistent-context-openai-realtime.py @@ -147,9 +147,8 @@ tools = ToolsSchema( ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/20c-persistent-context-anthropic.py b/examples/foundational/20c-persistent-context-anthropic.py index be70fd4b9..ae38ee7b7 100644 --- a/examples/foundational/20c-persistent-context-anthropic.py +++ b/examples/foundational/20c-persistent-context-anthropic.py @@ -166,24 +166,20 @@ tools = ToolsSchema( ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -218,6 +214,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/20d-persistent-context-gemini.py b/examples/foundational/20d-persistent-context-gemini.py index 4b434c4c1..145fe1151 100644 --- a/examples/foundational/20d-persistent-context-gemini.py +++ b/examples/foundational/20d-persistent-context-gemini.py @@ -238,21 +238,18 @@ tools = ToolsSchema( ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -284,6 +281,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/20e-persistent-context-aws-nova-sonic.py b/examples/foundational/20e-persistent-context-aws-nova-sonic.py index 10101f191..69ffb86b6 100644 --- a/examples/foundational/20e-persistent-context-aws-nova-sonic.py +++ b/examples/foundational/20e-persistent-context-aws-nova-sonic.py @@ -183,9 +183,8 @@ tools = ToolsSchema( ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/21a-tavus-video-service.py b/examples/foundational/21a-tavus-video-service.py index 0d68e2300..e9446975b 100644 --- a/examples/foundational/21a-tavus-video-service.py +++ b/examples/foundational/21a-tavus-video-service.py @@ -36,9 +36,8 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -47,7 +46,6 @@ transport_params = { video_out_is_live=True, video_out_width=1280, video_out_height=720, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -56,7 +54,6 @@ transport_params = { video_out_is_live=True, video_out_width=1280, video_out_height=720, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -95,6 +92,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/22-natural-conversation.py b/examples/foundational/22-natural-conversation.py index 1be12b7fa..94887daaf 100644 --- a/examples/foundational/22-natural-conversation.py +++ b/examples/foundational/22-natural-conversation.py @@ -12,6 +12,7 @@ from loguru import logger from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import LLMRunFrame, TextFrame from pipecat.pipeline.parallel_pipeline import ParallelPipeline from pipecat.pipeline.pipeline import Pipeline @@ -110,24 +111,20 @@ class TurnDetectionLLM(Pipeline): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -159,6 +156,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/22b-natural-conversation-proposal.py b/examples/foundational/22b-natural-conversation-proposal.py index 9a6d22494..5bcb16e6e 100644 --- a/examples/foundational/22b-natural-conversation-proposal.py +++ b/examples/foundational/22b-natural-conversation-proposal.py @@ -14,6 +14,7 @@ from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import ( CancelFrame, EndFrame, @@ -270,24 +271,20 @@ class TurnDetectionLLM(Pipeline): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -344,6 +341,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/22c-natural-conversation-mixed-llms.py b/examples/foundational/22c-natural-conversation-mixed-llms.py index 935aa5e36..e7565ffbe 100644 --- a/examples/foundational/22c-natural-conversation-mixed-llms.py +++ b/examples/foundational/22c-natural-conversation-mixed-llms.py @@ -14,6 +14,7 @@ from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import ( CancelFrame, EndFrame, @@ -473,24 +474,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -547,6 +544,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/22d-natural-conversation-gemini-audio.py b/examples/foundational/22d-natural-conversation-gemini-audio.py index 4a7c33a39..2ff1172f3 100644 --- a/examples/foundational/22d-natural-conversation-gemini-audio.py +++ b/examples/foundational/22d-natural-conversation-gemini-audio.py @@ -13,6 +13,7 @@ from loguru import logger from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import ( CancelFrame, EndFrame, @@ -703,24 +704,20 @@ class TurnDetectionLLM(Pipeline): ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -748,6 +745,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/23-bot-background-sound.py b/examples/foundational/23-bot-background-sound.py index 1cc944f26..75f9a3b21 100644 --- a/examples/foundational/23-bot-background-sound.py +++ b/examples/foundational/23-bot-background-sound.py @@ -41,9 +41,8 @@ OFFICE_SOUND_FILE = os.path.join( os.path.dirname(__file__), "assets", "office-ambience-24000-mono.mp3" ) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/24-user-mute-strategy.py b/examples/foundational/24-user-mute-strategy.py index 0797fc092..e55d8c3cb 100644 --- a/examples/foundational/24-user-mute-strategy.py +++ b/examples/foundational/24-user-mute-strategy.py @@ -52,24 +52,20 @@ async def fetch_weather_from_api(params: FunctionCallParams): await params.result_callback({"conditions": "nice", "temperature": "75"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -120,6 +116,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): MuteUntilFirstBotCompleteUserMuteStrategy(), FunctionCallUserMuteStrategy(), ], + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/25-google-audio-in.py b/examples/foundational/25-google-audio-in.py index 09f337d90..002aeaa1c 100644 --- a/examples/foundational/25-google-audio-in.py +++ b/examples/foundational/25-google-audio-in.py @@ -264,9 +264,8 @@ class TranscriptionContextFixup(FrameProcessor): await self.push_frame(frame, direction) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/26-gemini-live.py b/examples/foundational/26-gemini-live.py index a99d0db36..9a705fac1 100644 --- a/examples/foundational/26-gemini-live.py +++ b/examples/foundational/26-gemini-live.py @@ -15,6 +15,7 @@ from pipecat.frames.frames import LLMMessagesAppendFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask +from pipecat.processors.audio.vad_processor import VADProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.google.gemini_live.llm import GeminiLiveLLMService @@ -26,30 +27,26 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, # set stop_secs to something roughly similar to the internal setting # of the Multimodal Live api, just to align events. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, # set stop_secs to something roughly similar to the internal setting # of the Multimodal Live api, just to align events. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, # set stop_secs to something roughly similar to the internal setting # of the Multimodal Live api, just to align events. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -71,10 +68,13 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): voice_id="Puck", # Aoede, Charon, Fenrir, Kore, Puck ) + vad_processor = VADProcessor(vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5))) + # Build the pipeline pipeline = Pipeline( [ transport.input(), + vad_processor, llm, transport.output(), ] diff --git a/examples/foundational/26a-gemini-live-transcription.py b/examples/foundational/26a-gemini-live-transcription.py index c5a9e7d3b..96a719b10 100644 --- a/examples/foundational/26a-gemini-live-transcription.py +++ b/examples/foundational/26a-gemini-live-transcription.py @@ -20,6 +20,7 @@ from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.llm_response_universal import ( AssistantTurnStoppedMessage, LLMContextAggregatorPair, + LLMUserAggregatorParams, UserTurnStoppedMessage, ) from pipecat.runner.types import RunnerArguments @@ -32,36 +33,20 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -94,7 +79,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # }, ], ) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26b-gemini-live-function-calling.py b/examples/foundational/26b-gemini-live-function-calling.py index a16445630..7aea43036 100644 --- a/examples/foundational/26b-gemini-live-function-calling.py +++ b/examples/foundational/26b-gemini-live-function-calling.py @@ -20,7 +20,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.google.gemini_live.llm import GeminiLiveLLMService @@ -58,36 +61,20 @@ You have three tools available to you: """ -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -151,7 +138,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ], # tools, ) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26c-gemini-live-video.py b/examples/foundational/26c-gemini-live-video.py index 314765bab..4243f50d9 100644 --- a/examples/foundational/26c-gemini-live-video.py +++ b/examples/foundational/26c-gemini-live-video.py @@ -18,7 +18,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import ( create_transport, @@ -31,29 +34,18 @@ from pipecat.transports.daily.transport import DailyParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -74,7 +66,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): }, ], ) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26d-gemini-live-text.py b/examples/foundational/26d-gemini-live-text.py index c51f32d7b..1b3845fa3 100644 --- a/examples/foundational/26d-gemini-live-text.py +++ b/examples/foundational/26d-gemini-live-text.py @@ -17,7 +17,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.tts import CartesiaTTSService @@ -44,36 +47,20 @@ Respond to what the user said in a creative and helpful way. Keep your responses """ -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -111,7 +98,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Set up conversation context and management # The context_aggregator will automatically collect conversation context context = LLMContext(messages) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26e-gemini-live-google-search.py b/examples/foundational/26e-gemini-live-google-search.py index 9b37f32ee..64ab1962a 100644 --- a/examples/foundational/26e-gemini-live-google-search.py +++ b/examples/foundational/26e-gemini-live-google-search.py @@ -17,7 +17,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.google.gemini_live.llm import GeminiLiveLLMService @@ -46,36 +49,20 @@ Start each interaction by asking the user about which place they would like to k """ -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -99,7 +86,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): } ], ) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26f-gemini-live-files-api.py b/examples/foundational/26f-gemini-live-files-api.py index 3b9709869..4dcf2c10a 100644 --- a/examples/foundational/26f-gemini-live-files-api.py +++ b/examples/foundational/26f-gemini-live-files-api.py @@ -17,7 +17,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.google.gemini_live.llm import GeminiLiveLLMService @@ -28,27 +31,23 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -163,7 +162,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) # Create context aggregator - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) # Build the pipeline pipeline = Pipeline( diff --git a/examples/foundational/26g-gemini-live-groundingMetadata.py b/examples/foundational/26g-gemini-live-groundingMetadata.py index 1cf2be618..2868bfebc 100644 --- a/examples/foundational/26g-gemini-live-groundingMetadata.py +++ b/examples/foundational/26g-gemini-live-groundingMetadata.py @@ -11,7 +11,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport @@ -24,27 +27,23 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, video_in_enabled=False, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -126,7 +125,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Set up conversation context and management context = LLMContext(messages) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26h-gemini-live-vertex-function-calling.py b/examples/foundational/26h-gemini-live-vertex-function-calling.py index 35068e4c5..eb1db7934 100644 --- a/examples/foundational/26h-gemini-live-vertex-function-calling.py +++ b/examples/foundational/26h-gemini-live-vertex-function-calling.py @@ -20,7 +20,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.google.gemini_live.llm_vertex import GeminiLiveVertexLLMService @@ -57,36 +60,20 @@ You have three tools available to you: """ -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -139,7 +126,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm.register_function("get_restaurant_recommendation", fetch_restaurant_recommendation) context = LLMContext([{"role": "user", "content": "Say hello."}]) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/26i-gemini-live-graceful-end.py b/examples/foundational/26i-gemini-live-graceful-end.py index dae2bd109..54c8f0dfd 100644 --- a/examples/foundational/26i-gemini-live-graceful-end.py +++ b/examples/foundational/26i-gemini-live-graceful-end.py @@ -19,7 +19,10 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext -from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) from pipecat.processors.frame_processor import FrameDirection from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport @@ -67,36 +70,20 @@ After you've responded to the user three times, do two things, in order: """ -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - # set stop_secs to something roughly similar to the internal setting - # of the Multimodal Live api, just to align events. This doesn't really - # matter because we can only use the Multimodal Live API's phrase - # endpointing, for now. - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)), ), } @@ -156,7 +143,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): context = LLMContext( [{"role": "user", "content": "Say hello."}], ) - user_aggregator, assistant_aggregator = LLMContextAggregatorPair(context) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams( + # Set stop_secs to something roughly similar to the internal setting + # of the Multimodal Live api, just to align events. This doesn't + # really matter because we can only use the Multimodal Live API's + # phrase endpointing, for now. + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.5)) + ), + ) pipeline = Pipeline( [ diff --git a/examples/foundational/27-simli-layer.py b/examples/foundational/27-simli-layer.py index b89793c6b..7176b2a51 100644 --- a/examples/foundational/27-simli-layer.py +++ b/examples/foundational/27-simli-layer.py @@ -35,9 +35,8 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -46,7 +45,6 @@ transport_params = { video_out_is_live=True, video_out_width=512, video_out_height=512, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -55,7 +53,6 @@ transport_params = { video_out_is_live=True, video_out_width=512, video_out_height=512, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -91,6 +88,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/28-user-assistant-turns.py b/examples/foundational/28-user-assistant-turns.py index e870c836b..5d380cfc0 100644 --- a/examples/foundational/28-user-assistant-turns.py +++ b/examples/foundational/28-user-assistant-turns.py @@ -101,24 +101,20 @@ class TranscriptHandler: await self.save_message("assistant", message.content, message.timestamp) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -149,6 +145,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/29-turn-tracking-observer.py b/examples/foundational/29-turn-tracking-observer.py index 6a9391232..b6d8dcd88 100644 --- a/examples/foundational/29-turn-tracking-observer.py +++ b/examples/foundational/29-turn-tracking-observer.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -84,6 +80,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/30-observer.py b/examples/foundational/30-observer.py index e26e3280c..4d1567eed 100644 --- a/examples/foundational/30-observer.py +++ b/examples/foundational/30-observer.py @@ -83,24 +83,20 @@ class CustomObserver(BaseObserver): logger.info(f"🤖 BOT STOP SPEAKING: {src} {arrow} {dst} at {time_sec:.2f}s") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -131,6 +127,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/32-gemini-grounding-metadata.py b/examples/foundational/32-gemini-grounding-metadata.py index 7647287ed..910498800 100644 --- a/examples/foundational/32-gemini-grounding-metadata.py +++ b/examples/foundational/32-gemini-grounding-metadata.py @@ -78,24 +78,20 @@ class LLMSearchLoggerObserver(BaseObserver): logger.debug(f"🧠 {arrow} {dst} LLM SEARCH RESPONSE FRAME: {frame} at {time_sec:.2f}s") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -131,6 +127,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/33-gemini-rag.py b/examples/foundational/33-gemini-rag.py index 8df31426b..c8ad5eb97 100644 --- a/examples/foundational/33-gemini-rag.py +++ b/examples/foundational/33-gemini-rag.py @@ -162,24 +162,20 @@ async def query_knowledge_base(params: FunctionCallParams): await params.result_callback(response.text) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -232,6 +228,7 @@ Your response will be turned into speech so use only simple words and punctuatio user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/34-audio-recording.py b/examples/foundational/34-audio-recording.py index 6cbac25c6..687540f01 100644 --- a/examples/foundational/34-audio-recording.py +++ b/examples/foundational/34-audio-recording.py @@ -91,24 +91,20 @@ async def save_audio_file(audio: bytes, filename: str, sample_rate: int, num_cha logger.info(f"Audio saved to {filename}") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -142,6 +138,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/35-pattern-pair-voice-switching.py b/examples/foundational/35-pattern-pair-voice-switching.py index c90a39b39..26a346ae4 100644 --- a/examples/foundational/35-pattern-pair-voice-switching.py +++ b/examples/foundational/35-pattern-pair-voice-switching.py @@ -82,24 +82,20 @@ VOICE_IDS = { "male": "7cf0e2b1-8daf-4fe4-89ad-f6039398f359", # Male character voice } -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -207,6 +203,7 @@ Remember: Use narrator voice for EVERYTHING except the actual quoted dialogue."" user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/36-user-email-gathering.py b/examples/foundational/36-user-email-gathering.py index 1af985235..64bd72bcd 100644 --- a/examples/foundational/36-user-email-gathering.py +++ b/examples/foundational/36-user-email-gathering.py @@ -43,24 +43,20 @@ async def store_user_emails(params: FunctionCallParams): print(f"User emails: {params.arguments}") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -123,6 +119,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/37-mem0.py b/examples/foundational/37-mem0.py index 11eae51fb..f8ee7079e 100644 --- a/examples/foundational/37-mem0.py +++ b/examples/foundational/37-mem0.py @@ -132,24 +132,20 @@ async def get_initial_greeting( return "Hello! How can I help you today?" -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -252,6 +248,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/38-smart-turn-fal.py b/examples/foundational/38-smart-turn-fal.py index 05bbba5e9..8af8b58f8 100644 --- a/examples/foundational/38-smart-turn-fal.py +++ b/examples/foundational/38-smart-turn-fal.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -92,6 +88,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/38a-smart-turn-local-coreml.py b/examples/foundational/38a-smart-turn-local-coreml.py index 6500add0a..e2796d6a6 100644 --- a/examples/foundational/38a-smart-turn-local-coreml.py +++ b/examples/foundational/38a-smart-turn-local-coreml.py @@ -52,24 +52,20 @@ load_dotenv(override=True) # or add it to your .env file smart_turn_model_path = os.getenv("LOCAL_SMART_TURN_MODEL_PATH") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -106,6 +102,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/38b-smart-turn-local.py b/examples/foundational/38b-smart-turn-local.py index 85a320631..03ce79bc6 100644 --- a/examples/foundational/38b-smart-turn-local.py +++ b/examples/foundational/38b-smart-turn-local.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -83,6 +79,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/39-mcp-stdio.py b/examples/foundational/39-mcp-stdio.py index 02b4b2295..95237e6ad 100644 --- a/examples/foundational/39-mcp-stdio.py +++ b/examples/foundational/39-mcp-stdio.py @@ -112,9 +112,8 @@ def open_image_output_filter(output: str): print(f"🖼️ link to high resolution artwork: {text_to_print}") -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -122,7 +121,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -130,7 +128,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -200,6 +197,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/39a-mcp-streamable-http.py b/examples/foundational/39a-mcp-streamable-http.py index 6bd8fad61..27b9e5a36 100644 --- a/examples/foundational/39a-mcp-streamable-http.py +++ b/examples/foundational/39a-mcp-streamable-http.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -111,6 +107,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/39b-mcp-streamable-http-gemini-live.py b/examples/foundational/39b-mcp-streamable-http-gemini-live.py index 6294d9d71..38ac36f8f 100644 --- a/examples/foundational/39b-mcp-streamable-http-gemini-live.py +++ b/examples/foundational/39b-mcp-streamable-http-gemini-live.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -115,6 +111,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/39c-multiple-mcp.py b/examples/foundational/39c-multiple-mcp.py index 05cbe2b22..bb3dbd953 100644 --- a/examples/foundational/39c-multiple-mcp.py +++ b/examples/foundational/39c-multiple-mcp.py @@ -95,9 +95,8 @@ class UrlToImageProcessor(FrameProcessor): logger.error(error_msg) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -105,7 +104,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -113,7 +111,6 @@ transport_params = { video_out_enabled=True, video_out_width=1024, video_out_height=1024, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -200,6 +197,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) mcp_image_processor = UrlToImageProcessor(aiohttp_session=session) diff --git a/examples/foundational/40-aws-nova-sonic.py b/examples/foundational/40-aws-nova-sonic.py index f80bc5220..1bfa6063e 100644 --- a/examples/foundational/40-aws-nova-sonic.py +++ b/examples/foundational/40-aws-nova-sonic.py @@ -81,9 +81,8 @@ weather_function = FunctionSchema( tools = ToolsSchema(standard_tools=[weather_function]) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/42-interruption-config.py b/examples/foundational/42-interruption-config.py index c70e54c2d..f4279e80f 100644 --- a/examples/foundational/42-interruption-config.py +++ b/examples/foundational/42-interruption-config.py @@ -37,24 +37,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): start=[MinWordsUserTurnStartStrategy(min_words=3)], stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())], ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/43a-heygen-video-service.py b/examples/foundational/43a-heygen-video-service.py index 9257fbc77..294e907bf 100644 --- a/examples/foundational/43a-heygen-video-service.py +++ b/examples/foundational/43a-heygen-video-service.py @@ -36,9 +36,8 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, @@ -48,7 +47,6 @@ transport_params = { video_out_width=1280, video_out_height=720, video_out_bitrate=2_000_000, # 2MBps - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -57,7 +55,6 @@ transport_params = { video_out_is_live=True, video_out_width=1280, video_out_height=720, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -96,6 +93,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3()) ] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/44-voicemail-detection.py b/examples/foundational/44-voicemail-detection.py index baa76a05f..1ab1cdf7f 100644 --- a/examples/foundational/44-voicemail-detection.py +++ b/examples/foundational/44-voicemail-detection.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -86,6 +82,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/45-before-and-after-events.py b/examples/foundational/45-before-and-after-events.py index c6f9376e5..4664979e1 100644 --- a/examples/foundational/45-before-and-after-events.py +++ b/examples/foundational/45-before-and-after-events.py @@ -46,24 +46,20 @@ class CustomAfterPushFrame(DataFrame): pass -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -94,6 +90,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/46-video-processing.py b/examples/foundational/46-video-processing.py index bb3d57f04..ee490bfce 100644 --- a/examples/foundational/46-video-processing.py +++ b/examples/foundational/46-video-processing.py @@ -12,6 +12,7 @@ from loguru import logger from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3 from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import Frame, InputImageRawFrame, LLMRunFrame, OutputImageRawFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner @@ -40,7 +41,6 @@ transport_params = { video_in_enabled=True, video_out_enabled=True, video_out_is_live=True, - vad_analyzer=SileroVADAnalyzer(), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, @@ -49,7 +49,6 @@ transport_params = { video_in_enabled=True, video_out_enabled=True, video_out_is_live=True, - vad_analyzer=SileroVADAnalyzer(), ), } @@ -121,6 +120,7 @@ async def run_bot(pipecat_transport): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/47-sentry-metrics.py b/examples/foundational/47-sentry-metrics.py index 1b74210a1..85196f10a 100644 --- a/examples/foundational/47-sentry-metrics.py +++ b/examples/foundational/47-sentry-metrics.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -97,6 +93,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/48-service-switcher.py b/examples/foundational/48-service-switcher.py index 97b06a44a..e2b796018 100644 --- a/examples/foundational/48-service-switcher.py +++ b/examples/foundational/48-service-switcher.py @@ -60,24 +60,20 @@ async def get_restaurant_recommendation(params: FunctionCallParams, location: st await params.result_callback({"name": "The Golden Dragon"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -142,6 +138,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/49a-thinking-anthropic.py b/examples/foundational/49a-thinking-anthropic.py index d813aeee5..521a92282 100644 --- a/examples/foundational/49a-thinking-anthropic.py +++ b/examples/foundational/49a-thinking-anthropic.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -88,6 +84,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/49b-thinking-google.py b/examples/foundational/49b-thinking-google.py index 40cd48f31..223a77e1e 100644 --- a/examples/foundational/49b-thinking-google.py +++ b/examples/foundational/49b-thinking-google.py @@ -35,24 +35,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -93,6 +89,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/49c-thinking-functions-anthropic.py b/examples/foundational/49c-thinking-functions-anthropic.py index 33ea3ff0d..baa13b5d1 100644 --- a/examples/foundational/49c-thinking-functions-anthropic.py +++ b/examples/foundational/49c-thinking-functions-anthropic.py @@ -56,24 +56,20 @@ async def book_taxi(params: FunctionCallParams, time: str): await params.result_callback({"status": "done"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -114,6 +110,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/49d-thinking-functions-google.py b/examples/foundational/49d-thinking-functions-google.py index e00c3d00f..c03b37c0d 100644 --- a/examples/foundational/49d-thinking-functions-google.py +++ b/examples/foundational/49d-thinking-functions-google.py @@ -56,24 +56,20 @@ async def book_taxi(params: FunctionCallParams, time: str): await params.result_callback({"status": "done"}) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -119,6 +115,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): user_turn_strategies=UserTurnStrategies( stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())] ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/50-ultravox-realtime.py b/examples/foundational/50-ultravox-realtime.py index 51c298d77..5038cbb4c 100644 --- a/examples/foundational/50-ultravox-realtime.py +++ b/examples/foundational/50-ultravox-realtime.py @@ -29,9 +29,8 @@ from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, diff --git a/examples/foundational/52-live-translation.py b/examples/foundational/52-live-translation.py index 347c0a99e..6545d64c3 100644 --- a/examples/foundational/52-live-translation.py +++ b/examples/foundational/52-live-translation.py @@ -36,24 +36,20 @@ from pipecat.turns.user_turn_strategies import UserTurnStrategies load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -90,6 +86,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): start=[TranscriptionUserTurnStartStrategy(enable_interruptions=False)], stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())], ), + vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), ) diff --git a/examples/foundational/53-concurrent-llm-evaluation.py b/examples/foundational/53-concurrent-llm-evaluation.py index 432088574..7aff957a5 100644 --- a/examples/foundational/53-concurrent-llm-evaluation.py +++ b/examples/foundational/53-concurrent-llm-evaluation.py @@ -23,6 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams, ) +from pipecat.processors.audio.vad_processor import VADProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.tts import CartesiaTTSService @@ -39,24 +40,20 @@ from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies, UserT load_dotenv(override=True) -# We store functions so objects (e.g. SileroVADAnalyzer) don't get -# instantiated. The function will be called when the desired transport gets -# selected. +# We use lambdas to defer transport parameter creation until the transport +# type is selected at runtime. transport_params = { "daily": lambda: DailyParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "twilio": lambda: FastAPIWebsocketParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), "webrtc": lambda: TransportParams( audio_in_enabled=True, audio_out_enabled=True, - vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), ), } @@ -68,7 +65,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady + voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady ) openai_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) @@ -94,6 +91,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): openai_context = LLMContext(openai_messages) groq_context = LLMContext(groq_messages) + # We use an external VADProcessor because the UserTurnProcessor is shared + # across multiple parallel aggregators. The VADProcessor emits + # VADUserStartedSpeakingFrame and VADUserStoppedSpeakingFrame which the + # UserTurnProcessor needs to manage turn lifecycle. + vad_processor = VADProcessor(vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2))) + # We use this external user turn processor. This processor will push # UserStartedSpeakingFrame and UserStoppedSpeakingFrame as well as # interruptions. This can be used in advanced cases when there are multiple @@ -119,6 +122,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): [ transport.input(), # Transport user input stt, # STT + vad_processor, user_turn_processor, ParallelPipeline( [ diff --git a/src/pipecat/audio/vad/vad_analyzer.py b/src/pipecat/audio/vad/vad_analyzer.py index a96b025dd..254b0619e 100644 --- a/src/pipecat/audio/vad/vad_analyzer.py +++ b/src/pipecat/audio/vad/vad_analyzer.py @@ -127,7 +127,7 @@ class VADAnalyzer(ABC): pass @abstractmethod - def voice_confidence(self, buffer) -> float: + def voice_confidence(self, buffer: bytes) -> float: """Calculate voice activity confidence for the given audio buffer. Args: diff --git a/src/pipecat/audio/vad/vad_controller.py b/src/pipecat/audio/vad/vad_controller.py new file mode 100644 index 000000000..66f7199e5 --- /dev/null +++ b/src/pipecat/audio/vad/vad_controller.py @@ -0,0 +1,169 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +"""Voice Activity Detection controller for managing speech state transitions. + +This module provides a controller that wraps a VADAnalyzer to track speech state +and emit events when speech starts, stops, or is actively detected. +""" + +import time +from typing import Type + +from pipecat.audio.vad.vad_analyzer import VADAnalyzer, VADState +from pipecat.frames.frames import ( + Frame, + InputAudioRawFrame, + SpeechControlParamsFrame, + StartFrame, + VADParamsUpdateFrame, +) +from pipecat.processors.frame_processor import FrameDirection +from pipecat.utils.base_object import BaseObject + + +class VADController(BaseObject): + """Manages voice activity detection state and emits speech events. + + Wraps a `VADAnalyzer` to process audio and trigger events based on speech + state transitions. Tracks whether the user is speaking, quiet, or + transitioning between states. + + Event handlers available: + + - on_speech_started: Called when speech begins. + - on_speech_stopped: Called when speech ends. + - on_speech_activity: Called periodically while speech is detected. + - on_push_frame: Called when the controller wants to push a frame. + - on_broadcast_frame: Called when the controller wants to broadcast a frame. + + Example:: + + @vad_controller.event_handler("on_speech_started") + async def on_speech_started(controller): + ... + + @vad_controller.event_handler("on_speech_stopped") + async def on_speech_stopped(controller): + ... + + @vad_controller.event_handler("on_speech_activity") + async def on_speech_activity(controller): + ... + + @vad_controller.event_handler("on_push_frame") + async def on_push_frame(controller, frame: Frame, direction: FrameDirection): + ... + + @vad_controller.event_handler("on_broadcast_frame") + async def on_broadcast_frame(controller, frame_cls: Type[Frame], **kwargs): + ... + """ + + def __init__(self, vad_analyzer: VADAnalyzer, *, speech_activity_period: float = 0.2): + """Initialize the VAD controller. + + Args: + vad_analyzer: The `VADAnalyzer` instance for processing audio. + speech_activity_period: Minimum interval in seconds between + `on_speech_activity` events. Defaults to 0.2. + """ + super().__init__() + self._vad_analyzer = vad_analyzer + self._vad_state: VADState = VADState.QUIET + + # Last time a on_speech_activity was triggered. + self._speech_activity_time = 0 + # How often a on_speech_activity event should be triggered (value should + # be greater than the audio chunks to have any effect). + self._speech_activity_period = speech_activity_period + + self._register_event_handler("on_speech_started", sync=True) + self._register_event_handler("on_speech_stopped", sync=True) + self._register_event_handler("on_speech_activity", sync=True) + self._register_event_handler("on_push_frame", sync=True) + self._register_event_handler("on_broadcast_frame", sync=True) + + async def process_frame(self, frame: Frame): + """Process a frame and handle VAD-related events. + + Handles `StartFrame` to initialize the sample rate and `InputAudioRawFrame` + to analyze audio for voice activity. + + Args: + frame: The frame to process. + """ + if isinstance(frame, StartFrame): + await self._start(frame) + elif isinstance(frame, InputAudioRawFrame): + await self._handle_audio(frame) + elif isinstance(frame, VADParamsUpdateFrame): + self._vad_analyzer.set_params(frame.params) + await self.broadcast_frame(SpeechControlParamsFrame, vad_params=frame.params) + + async def _start(self, frame: StartFrame): + self._vad_analyzer.set_sample_rate(frame.audio_in_sample_rate) + + async def _handle_audio(self, frame: InputAudioRawFrame): + """Process an audio chunk and emit speech events as needed. + + Analyzes the audio for voice activity and triggers `on_speech_started`, + `on_speech_stopped`, or `on_speech_activity` events based on state changes. + + Args: + frame: Audio frame to process. + """ + self._vad_state = await self._handle_vad(frame.audio, self._vad_state) + + if self._vad_state == VADState.SPEAKING: + await self._call_event_handler("on_speech_activity") + + async def _handle_vad(self, audio: bytes, vad_state: VADState) -> VADState: + """Handle Voice Activity Detection results and trigger appropriate events.""" + new_vad_state = await self._vad_analyzer.analyze_audio(audio) + if ( + new_vad_state != vad_state + and new_vad_state != VADState.STARTING + and new_vad_state != VADState.STOPPING + ): + if new_vad_state == VADState.SPEAKING: + await self._call_event_handler("on_speech_started") + elif new_vad_state == VADState.QUIET: + await self._call_event_handler("on_speech_stopped") + + vad_state = new_vad_state + return vad_state + + async def _maybe_speech_activity(self): + """Handle user speaking frame.""" + diff_time = time.time() - self._speech_activity_time + if diff_time >= self._speech_activity_period: + self._speech_activity_time = time.time() + await self._call_event_handler("on_speech_activity") + + async def push_frame(self, frame: Frame, direction: FrameDirection = FrameDirection.DOWNSTREAM): + """Request a frame to be pushed through the pipeline. + + This emits an on_push_frame event that must be handled by a processor + to actually push the frame into the pipeline. + + Args: + frame: The frame to push. + direction: The direction to push the frame. + """ + await self._call_event_handler("on_push_frame", frame, direction) + + async def broadcast_frame(self, frame_cls: Type[Frame], **kwargs): + """Request a frame to be broadcast upstream and downstream. + + This emits an on_broadcast_frame event that must be handled by a processor + to actually broadcast the frame in the pipeline. + + Args: + frame_cls: The class of the frame to broadcast. + **kwargs: Arguments to pass to the frame constructor. + """ + await self._call_event_handler("on_broadcast_frame", frame_cls, **kwargs) diff --git a/src/pipecat/processors/aggregators/llm_response_universal.py b/src/pipecat/processors/aggregators/llm_response_universal.py index 200010591..5d3432929 100644 --- a/src/pipecat/processors/aggregators/llm_response_universal.py +++ b/src/pipecat/processors/aggregators/llm_response_universal.py @@ -21,6 +21,8 @@ from typing import Any, Dict, List, Literal, Optional, Set, Type from loguru import logger from pipecat.adapters.schemas.tools_schema import ToolsSchema +from pipecat.audio.vad.vad_analyzer import VADAnalyzer +from pipecat.audio.vad.vad_controller import VADController from pipecat.frames.frames import ( AssistantImageRawFrame, CancelFrame, @@ -50,6 +52,7 @@ from pipecat.frames.frames import ( TextFrame, TranscriptionFrame, UserImageRawFrame, + UserSpeakingFrame, UserStartedSpeakingFrame, UserStoppedSpeakingFrame, VADUserStartedSpeakingFrame, @@ -61,7 +64,7 @@ from pipecat.processors.aggregators.llm_context import ( LLMSpecificMessage, NotGiven, ) -from pipecat.processors.frame_processor import FrameDirection, FrameProcessor +from pipecat.processors.frame_processor import FrameCallback, FrameDirection, FrameProcessor from pipecat.turns.user_idle_controller import UserIdleController from pipecat.turns.user_mute import BaseUserMuteStrategy from pipecat.turns.user_start import BaseUserTurnStartStrategy, UserTurnStartedParams @@ -85,12 +88,14 @@ class LLMUserAggregatorParams: If set, the aggregator will emit an `on_user_turn_idle` event when the user has been idle (not speaking) for this duration. Set to None to disable idle detection. + vad_analyzer: Voice Activity Detection analyzer instance. """ user_turn_strategies: Optional[UserTurnStrategies] = None user_mute_strategies: List[BaseUserMuteStrategy] = field(default_factory=list) user_turn_stop_timeout: float = 5.0 user_idle_timeout: Optional[float] = None + vad_analyzer: Optional[VADAnalyzer] = None @dataclass @@ -384,6 +389,23 @@ class LLMUserAggregator(LLMContextAggregator): "on_user_turn_idle", self._on_user_turn_idle ) + # VAD controller + self._vad_controller: Optional[VADController] = None + if self._params.vad_analyzer: + self._vad_controller = VADController(self._params.vad_analyzer) + self._vad_controller.add_event_handler("on_speech_started", self._on_vad_speech_started) + self._vad_controller.add_event_handler("on_speech_stopped", self._on_vad_speech_stopped) + self._vad_controller.add_event_handler( + "on_speech_activity", self._on_vad_speech_activity + ) + self._vad_controller.add_event_handler("on_push_frame", self._on_push_frame) + self._vad_controller.add_event_handler("on_broadcast_frame", self._on_broadcast_frame) + + # NOTE(aleix): Probably just needed temporarily. This was added to + # prevent processing self-queued frames (SpeechControlParamsFrame) + # pushed by strategies. + self._self_queued_frames = set() + async def cleanup(self): """Clean up processor resources.""" await super().cleanup() @@ -401,6 +423,9 @@ class LLMUserAggregator(LLMContextAggregator): if await self._maybe_mute_frame(frame): return + if self._vad_controller: + await self._vad_controller.process_frame(frame) + if isinstance(frame, StartFrame): # Push StartFrame before start(), because we want StartFrame to be # processed by every processor before any other frame is processed. @@ -528,6 +553,9 @@ class LLMUserAggregator(LLMContextAggregator): await self.push_context_frame() async def _handle_speech_control_params(self, frame: SpeechControlParamsFrame): + if frame.id in self._self_queued_frames: + return + if not frame.turn_params: return @@ -567,13 +595,47 @@ class LLMUserAggregator(LLMContextAggregator): ) ) + async def _internal_queue_frame( + self, + frame: Frame, + direction: FrameDirection = FrameDirection.DOWNSTREAM, + callback: Optional[FrameCallback] = None, + ): + """Queues the given frame to ourselves.""" + self._self_queued_frames.add(frame.id) + await self.queue_frame(frame, direction, callback) + + async def _queued_broadcast_frame(self, frame_cls: Type[Frame], **kwargs): + """Broadcasts a frame upstream and queues it for internal processing. + + Queues the frame so it flows through `process_frame` and is handled + internally (e.g. by the `UserTurnController`). The upstream frame is + pushed directly. + + Args: + frame_cls: The class of the frame to be broadcasted. + **kwargs: Keyword arguments to be passed to the frame's constructor. + + """ + await self._internal_queue_frame(frame_cls(**kwargs)) + await self.push_frame(frame_cls(**kwargs), FrameDirection.UPSTREAM) + async def _on_push_frame( self, controller, frame: Frame, direction: FrameDirection = FrameDirection.DOWNSTREAM ): - await self.push_frame(frame, direction) + await self._internal_queue_frame(frame, direction) async def _on_broadcast_frame(self, controller, frame_cls: Type[Frame], **kwargs): - await self.broadcast_frame(frame_cls, **kwargs) + await self._queued_broadcast_frame(frame_cls, **kwargs) + + async def _on_vad_speech_started(self, controller): + await self._queued_broadcast_frame(VADUserStartedSpeakingFrame) + + async def _on_vad_speech_stopped(self, controller): + await self._queued_broadcast_frame(VADUserStoppedSpeakingFrame) + + async def _on_vad_speech_activity(self, controller): + await self._queued_broadcast_frame(UserSpeakingFrame) async def _on_user_turn_started( self, diff --git a/src/pipecat/processors/audio/vad_processor.py b/src/pipecat/processors/audio/vad_processor.py new file mode 100644 index 000000000..074ea57e6 --- /dev/null +++ b/src/pipecat/processors/audio/vad_processor.py @@ -0,0 +1,100 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +"""Voice Activity Detection processor for detecting speech in audio streams. + +This module provides a VADProcessor that wraps a VADController to process +audio frames and push VAD-related frames into the pipeline. +""" + +from typing import Type + +from loguru import logger + +from pipecat.audio.vad.vad_analyzer import VADAnalyzer +from pipecat.audio.vad.vad_controller import VADController +from pipecat.frames.frames import ( + Frame, + UserSpeakingFrame, + VADUserStartedSpeakingFrame, + VADUserStoppedSpeakingFrame, +) +from pipecat.processors.frame_processor import FrameDirection, FrameProcessor + + +class VADProcessor(FrameProcessor): + """Processes audio frames through voice activity detection. + + This processor wraps a VADController to detect speech in audio streams + and push VAD frames into the pipeline: + + - ``VADUserStartedSpeakingFrame``: Pushed when speech begins. + - ``VADUserStoppedSpeakingFrame``: Pushed when speech ends. + - ``UserSpeakingFrame``: Pushed periodically while speech is detected. + + Example:: + + vad_processor = VADProcessor(vad_analyzer=SileroVADAnalyzer()) + """ + + def __init__( + self, + *, + vad_analyzer: VADAnalyzer, + speech_activity_period: float = 0.2, + **kwargs, + ): + """Initialize the VAD processor. + + Args: + vad_analyzer: The VADAnalyzer instance for processing audio. + speech_activity_period: Minimum interval in seconds between + UserSpeakingFrame pushes. Defaults to 0.2. + **kwargs: Additional arguments passed to parent class. + """ + super().__init__(**kwargs) + self._vad_controller = VADController( + vad_analyzer, speech_activity_period=speech_activity_period + ) + + # Push VAD frames when speech events are detected + @self._vad_controller.event_handler("on_speech_started") + async def on_speech_started(_controller): + logger.debug(f"{self}: User started speaking") + await self.broadcast_frame(VADUserStartedSpeakingFrame) + + @self._vad_controller.event_handler("on_speech_stopped") + async def on_speech_stopped(_controller): + logger.debug(f"{self}: User stopped speaking") + await self.broadcast_frame(VADUserStoppedSpeakingFrame) + + @self._vad_controller.event_handler("on_speech_activity") + async def on_speech_activity(_controller): + await self.broadcast_frame(UserSpeakingFrame) + + # Wire up frame pushing from controller to processor + @self._vad_controller.event_handler("on_push_frame") + async def on_push_frame(_controller, frame: Frame, direction: FrameDirection): + await self.push_frame(frame, direction) + + @self._vad_controller.event_handler("on_broadcast_frame") + async def on_broadcast_frame(_controller, frame_cls: Type[Frame], **kwargs): + await self.broadcast_frame(frame_cls, **kwargs) + + async def process_frame(self, frame: Frame, direction: FrameDirection): + """Process a frame through VAD and forward it. + + Args: + frame: The frame to process. + direction: The direction of frame flow in the pipeline. + """ + await super().process_frame(frame, direction) + + # Let the VAD controller handle the frame + await self._vad_controller.process_frame(frame) + + # Always forward the frame + await self.push_frame(frame, direction) diff --git a/src/pipecat/services/nvidia/tts.py b/src/pipecat/services/nvidia/tts.py index eddafce01..e90462ad9 100644 --- a/src/pipecat/services/nvidia/tts.py +++ b/src/pipecat/services/nvidia/tts.py @@ -12,7 +12,7 @@ gRPC API for high-quality speech synthesis. import asyncio import os -from typing import AsyncGenerator, AsyncIterable, Generator, Mapping, Optional +from typing import AsyncGenerator, AsyncIterator, Generator, Mapping, Optional from pipecat.utils.tracing.service_decorators import traced_tts @@ -181,7 +181,7 @@ class NvidiaTTSService(TTSService): except StopIteration: return None - async def async_iterator(iterator) -> AsyncIterable[rtts.SynthesizeSpeechResponse]: + async def async_iterator(iterator) -> AsyncIterator[rtts.SynthesizeSpeechResponse]: while True: item = await asyncio.to_thread(async_next, iterator) if item is None: diff --git a/src/pipecat/transports/base_input.py b/src/pipecat/transports/base_input.py index b5f5a17c7..5f62045f1 100644 --- a/src/pipecat/transports/base_input.py +++ b/src/pipecat/transports/base_input.py @@ -48,7 +48,7 @@ from pipecat.metrics.metrics import MetricsData from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.transports.base_transport import TransportParams -AUDIO_INPUT_TIMEOUT_SECS = 0.5 +AUDIO_INPUT_TIMEOUT_SECS = 1.0 class BaseInputTransport(FrameProcessor): @@ -144,6 +144,17 @@ class BaseInputTransport(FrameProcessor): DeprecationWarning, ) + if self._params.vad_analyzer: + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn( + "Parameter 'vad_analyzer' is deprecated, use `LLMUserAggregator`'s new " + "`vad_analyzer` parameter instead.", + DeprecationWarning, + ) + def enable_audio_in_stream_on_start(self, enabled: bool) -> None: """Enable or disable audio streaming on transport start. @@ -173,9 +184,23 @@ class BaseInputTransport(FrameProcessor): def vad_analyzer(self) -> Optional[VADAnalyzer]: """Get the Voice Activity Detection analyzer. + .. deprecated:: 0.0.101 + This method is deprecated and will be removed in a future version. + Use `LLMUserAggregator`'s new `vad_analyzer` parameter instead. + Returns: The VAD analyzer instance if configured, None otherwise. """ + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn( + "Method 'vad_analyzer' is deprecated. Use `LLMUserAggregator`'s new " + "`vad_analyzer` parameter instead.", + DeprecationWarning, + ) + return self._params.vad_analyzer @property @@ -212,6 +237,13 @@ class BaseInputTransport(FrameProcessor): self._sample_rate = self._params.audio_in_sample_rate or frame.audio_in_sample_rate + # Start audio filter. + if self._params.audio_in_filter: + await self._params.audio_in_filter.start(self._sample_rate) + + ################################################################### + # DEPRECATED. + # Configure VAD analyzer. if self._params.vad_analyzer: self._params.vad_analyzer.set_sample_rate(self._sample_rate) @@ -227,10 +259,7 @@ class BaseInputTransport(FrameProcessor): await self.broadcast_frame( SpeechControlParamsFrame, vad_params=vad_params, turn_params=turn_params ) - - # Start audio filter. - if self._params.audio_in_filter: - await self._params.audio_in_filter.start(self._sample_rate) + ################################################################### async def stop(self, frame: EndFrame): """Stop the input transport and cleanup resources. @@ -341,9 +370,11 @@ class BaseInputTransport(FrameProcessor): elif isinstance(frame, StopFrame): await self.push_frame(frame, direction) await self.pause(frame) + ################################################################### + # DEPRECATED. elif isinstance(frame, VADParamsUpdateFrame): - if self.vad_analyzer: - self.vad_analyzer.set_params(frame.params) + if self._params.vad_analyzer: + self._params.vad_analyzer.set_params(frame.params) await self.broadcast_frame( SpeechControlParamsFrame, vad_params=frame.params, @@ -351,6 +382,7 @@ class BaseInputTransport(FrameProcessor): if self._params.turn_analyzer else None, ) + ################################################################### elif isinstance(frame, FilterUpdateSettingsFrame) and self._params.audio_in_filter: await self._params.audio_in_filter.process_frame(frame) # Other frames @@ -373,18 +405,89 @@ class BaseInputTransport(FrameProcessor): await self.cancel_task(self._audio_task) self._audio_task = None - async def _vad_analyze(self, audio_frame: InputAudioRawFrame) -> VADState: + async def _audio_task_handler(self): + """Main audio processing task handler for VAD and turn analysis.""" + vad_state: VADState = VADState.QUIET + # Skip timeout handling until the first audio frame arrives (e.g. client + # not yet connected). + audio_received = False + while True: + try: + frame: InputAudioRawFrame = await asyncio.wait_for( + self._audio_in_queue.get(), timeout=AUDIO_INPUT_TIMEOUT_SECS + ) + + # From now on, timeout should warn if there's no audio. + audio_received = True + + # If an audio filter is available, run it before VAD. + if self._params.audio_in_filter: + frame.audio = await self._params.audio_in_filter.filter(frame.audio) + + ################################################################### + # DEPRECATED. + # + # Check VAD and push event if necessary. We just care about + # changes from QUIET to SPEAKING and vice versa. + previous_vad_state = vad_state + if self._params.vad_analyzer: + vad_state = await self._deprecated_handle_vad(frame, vad_state) + + if self._params.turn_analyzer: + await self._deprecated_run_turn_analyzer(frame, vad_state, previous_vad_state) + + if self._params.vad_analyzer and vad_state == VADState.SPEAKING: + await self._deprecated_user_currently_speaking() + ################################################################### + + # Push audio downstream if passthrough is set. + if self._params.audio_in_passthrough: + await self.push_frame(frame) + + self._audio_in_queue.task_done() + except asyncio.TimeoutError: + if not audio_received: + continue + + logger.warning( + f"{self}: audio not received for more than {AUDIO_INPUT_TIMEOUT_SECS}" + ) + + ################################################################### + # DEPRECATED. + if self._user_speaking: + logger.warning( + "Forcing VAD user stopped speaking due to timeout receiving audio frame!" + ) + vad_state = VADState.QUIET + if self._params.turn_analyzer: + self._params.turn_analyzer.clear() + + if self._params.turn_analyzer: + await self._deprecated_handle_user_interruption(VADState.QUIET) + else: + await self.push_frame(VADUserStoppedSpeakingFrame()) + ################################################################### + + # + # DEPRECATED. + # + # The functions below are deprecated and should be removed once the old + # interruption strategies and turn analyzer are removed. + # + + async def _deprecated_vad_analyze(self, audio_frame: InputAudioRawFrame) -> VADState: """Analyze audio frame for voice activity.""" state = VADState.QUIET - if self.vad_analyzer: - state = await self.vad_analyzer.analyze_audio(audio_frame.audio) + if self._params.vad_analyzer: + state = await self._params.vad_analyzer.analyze_audio(audio_frame.audio) return state - async def _new_handle_vad( + async def _deprecated_new_handle_vad( self, audio_frame: InputAudioRawFrame, vad_state: VADState ) -> VADState: """Handle Voice Activity Detection results and generate appropriate frames.""" - new_vad_state = await self._vad_analyze(audio_frame) + new_vad_state = await self._deprecated_vad_analyze(audio_frame) if ( new_vad_state != vad_state and new_vad_state != VADState.STARTING @@ -398,72 +501,22 @@ class BaseInputTransport(FrameProcessor): vad_state = new_vad_state return vad_state - async def _handle_vad(self, audio_frame: InputAudioRawFrame, vad_state: VADState) -> VADState: + async def _deprecated_handle_vad( + self, audio_frame: InputAudioRawFrame, vad_state: VADState + ) -> VADState: """Handle Voice Activity Detection results and generate appropriate frames.""" if self._params.turn_analyzer or self._deprecated_openaillmcontext: - return await self._deprecated_handle_vad(audio_frame, vad_state) + return await self._deprecated_old_handle_vad(audio_frame, vad_state) else: - return await self._new_handle_vad(audio_frame, vad_state) + return await self._deprecated_new_handle_vad(audio_frame, vad_state) - async def _audio_task_handler(self): - """Main audio processing task handler for VAD and turn analysis.""" - vad_state: VADState = VADState.QUIET - while True: - try: - frame: InputAudioRawFrame = await asyncio.wait_for( - self._audio_in_queue.get(), timeout=AUDIO_INPUT_TIMEOUT_SECS - ) - - # If an audio filter is available, run it before VAD. - if self._params.audio_in_filter: - frame.audio = await self._params.audio_in_filter.filter(frame.audio) - - # Check VAD and push event if necessary. We just care about - # changes from QUIET to SPEAKING and vice versa. - previous_vad_state = vad_state - if self._params.vad_analyzer: - vad_state = await self._handle_vad(frame, vad_state) - - # DEPRECATED. - if self._params.turn_analyzer: - await self._deprecated_run_turn_analyzer(frame, vad_state, previous_vad_state) - - if vad_state == VADState.SPEAKING: - await self._user_currently_speaking() - - # Push audio downstream if passthrough is set. - if self._params.audio_in_passthrough: - await self.push_frame(frame) - - self._audio_in_queue.task_done() - except asyncio.TimeoutError: - if self._user_speaking: - logger.warning( - "Forcing VAD user stopped speaking due to timeout receiving audio frame!" - ) - vad_state = VADState.QUIET - if self._params.turn_analyzer: - self._params.turn_analyzer.clear() - - if self._params.turn_analyzer: - await self._deprecated_handle_user_interruption(VADState.QUIET) - else: - await self.push_frame(VADUserStoppedSpeakingFrame()) - - async def _user_currently_speaking(self): + async def _deprecated_user_currently_speaking(self): """Handle user speaking frame.""" diff_time = time.time() - self._user_speaking_frame_time if diff_time >= self._user_speaking_frame_period: await self.broadcast_frame(UserSpeakingFrame) self._user_speaking_frame_time = time.time() - # - # DEPRECATED. - # - # The functions below are deprecated and should be removed once the old - # interruption strategies and turn analyzer are removed. - # - async def _deprecated_handle_bot_started_speaking(self, frame: BotStartedSpeakingFrame): """Update bot speaking state when bot starts speaking.""" self._bot_speaking = True @@ -503,11 +556,11 @@ class BaseInputTransport(FrameProcessor): await self.broadcast_frame(UserStoppedSpeakingFrame, emulated=emulated) - async def _deprecated_handle_vad( + async def _deprecated_old_handle_vad( self, audio_frame: InputAudioRawFrame, vad_state: VADState ) -> VADState: """Handle Voice Activity Detection results and generate appropriate frames.""" - new_vad_state = await self._vad_analyze(audio_frame) + new_vad_state = await self._deprecated_vad_analyze(audio_frame) if ( new_vad_state != vad_state and new_vad_state != VADState.STARTING @@ -539,9 +592,7 @@ class BaseInputTransport(FrameProcessor): async def _deprecated_handle_end_of_turn(self): """Handle end-of-turn analysis and generate prediction results.""" - # Don't use self._params.turn_analyzer so we can keep showing one - # deprecation warning. - if self.turn_analyzer: + if self._params.turn_analyzer: state, prediction = await self._params.turn_analyzer.analyze_end_of_turn() await self._deprecated_handle_prediction_result(prediction) await self._deprecated_handle_end_of_turn_complete(state) diff --git a/src/pipecat/transports/base_transport.py b/src/pipecat/transports/base_transport.py index bbdd7fcfc..7879976ba 100644 --- a/src/pipecat/transports/base_transport.py +++ b/src/pipecat/transports/base_transport.py @@ -113,6 +113,11 @@ class TransportParams(BaseModel): instead. vad_analyzer: Voice Activity Detection analyzer instance. + + .. deprecated:: 0.0.101 + The `vad_analyzer` parameter is deprecated, use `LLMUSerAggregator`'s + new `vad_analyzer` parameter instead. + turn_analyzer: Turn-taking analyzer instance for conversation management. .. deprecated:: 0.0.99 diff --git a/src/pipecat/turns/user_stop/turn_analyzer_user_turn_stop_strategy.py b/src/pipecat/turns/user_stop/turn_analyzer_user_turn_stop_strategy.py index 1bb266380..109359c2a 100644 --- a/src/pipecat/turns/user_stop/turn_analyzer_user_turn_stop_strategy.py +++ b/src/pipecat/turns/user_stop/turn_analyzer_user_turn_stop_strategy.py @@ -113,7 +113,8 @@ class TurnAnalyzerUserTurnStopStrategy(BaseUserTurnStopStrategy): audio collected during that confirmation window, so we let the analyzer know when this value has changed. """ - self._turn_analyzer.update_vad_start_secs(frame.vad_params.start_secs) + if frame.vad_params: + self._turn_analyzer.update_vad_start_secs(frame.vad_params.start_secs) async def _handle_input_audio(self, frame: InputAudioRawFrame): """Handle input audio to check if the turn is completed.""" diff --git a/tests/test_aggregators.py b/tests/test_aggregators.py index 73ccf6b04..6563d324c 100644 --- a/tests/test_aggregators.py +++ b/tests/test_aggregators.py @@ -74,3 +74,7 @@ class TestGatedAggregator(unittest.IsolatedAsyncioTestCase): frames_to_send=frames_to_send, expected_down_frames=expected_down_frames, ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_audio_buffer_processor.py b/tests/test_audio_buffer_processor.py index faebe4ef5..4d3c588bc 100644 --- a/tests/test_audio_buffer_processor.py +++ b/tests/test_audio_buffer_processor.py @@ -115,3 +115,7 @@ class TestAudioBufferProcessor(unittest.IsolatedAsyncioTestCase): self.assertEqual(merged_audio[6:8], bot_audio[2:4]) self.assertEqual(len(self.processor._user_audio_buffer), 0) self.assertEqual(len(self.processor._bot_audio_buffer), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_context_aggregators.py b/tests/test_context_aggregators.py index 17a24113e..24dae0b4c 100644 --- a/tests/test_context_aggregators.py +++ b/tests/test_context_aggregators.py @@ -1055,3 +1055,7 @@ class TestLLMAssistantAggregator( 0, "Hello Pipecat. Here's some code: ```python\nprint('Hello, World!')\n``` ```javascript\nconsole.log('Hello, World!');\n``` And some more: ```html\n
Hello, World!
\n``` Hope that helps!", ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_context_aggregators_universal.py b/tests/test_context_aggregators_universal.py index 63f1fef9a..e840fd8f5 100644 --- a/tests/test_context_aggregators_universal.py +++ b/tests/test_context_aggregators_universal.py @@ -566,3 +566,7 @@ class TestLLMAssistantAggregator(unittest.IsolatedAsyncioTestCase): # The pending text should be emitted on EndFrame self.assertEqual(len(stop_messages), 1) self.assertEqual(stop_messages[0].content, "Hello from Pipecat!") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_daily_transport_service.py b/tests/test_daily_transport_service.py index 5ebf28b83..117c859ce 100644 --- a/tests/test_daily_transport_service.py +++ b/tests/test_daily_transport_service.py @@ -90,3 +90,7 @@ class TestDailyTransport(unittest.IsolatedAsyncioTestCase): camera.write_frame.assert_called_with(b"test") mic.write_frames.assert_called() """ + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_dtmf_aggregator.py b/tests/test_dtmf_aggregator.py index dd9f4d835..827720b9c 100644 --- a/tests/test_dtmf_aggregator.py +++ b/tests/test_dtmf_aggregator.py @@ -240,3 +240,7 @@ class TestDTMFAggregator(unittest.IsolatedAsyncioTestCase): ] self.assertEqual(len(transcription_frames), 1) self.assertEqual(transcription_frames[0].text, "DTMF: 0123456789*#") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_filters.py b/tests/test_filters.py index 1d56fab38..b62239aeb 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -118,3 +118,7 @@ class TestWakeCheckFilter(unittest.IsolatedAsyncioTestCase): expected_down_frames=expected_down_frames, ) assert received_down[-1].text == "Phrase 1" + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_frame_processor.py b/tests/test_frame_processor.py index 2df35a10e..f44181858 100644 --- a/tests/test_frame_processor.py +++ b/tests/test_frame_processor.py @@ -347,3 +347,7 @@ class TestFrameProcessor(unittest.IsolatedAsyncioTestCase): self.assertIs(up_frame.items, orig.items) self.assertIs(down_frame.metadata, orig.metadata) self.assertIs(up_frame.metadata, orig.metadata) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_function_calling_adapters.py b/tests/test_function_calling_adapters.py index 5df59ed79..348754f47 100644 --- a/tests/test_function_calling_adapters.py +++ b/tests/test_function_calling_adapters.py @@ -204,3 +204,7 @@ class TestFunctionAdapters(unittest.TestCase): } ] assert AWSBedrockLLMAdapter().to_provider_tools_format(self.tools_def) == expected + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_interruption_strategies.py b/tests/test_interruption_strategies.py index 220649a53..d4aff2a7a 100644 --- a/tests/test_interruption_strategies.py +++ b/tests/test_interruption_strategies.py @@ -22,3 +22,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase): self.assertEqual(await strategy.should_interrupt(), False) await strategy.append_text(" How are you?") self.assertEqual(await strategy.should_interrupt(), True) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_ivr_navigation.py b/tests/test_ivr_navigation.py index 420ea2c2f..ee43bdf62 100644 --- a/tests/test_ivr_navigation.py +++ b/tests/test_ivr_navigation.py @@ -353,3 +353,7 @@ class TestIVRNavigation(unittest.IsolatedAsyncioTestCase): expected_down_frames=expected_down_frames, expected_up_frames=expected_up_frames, ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_krisp_sdk_manager.py b/tests/test_krisp_sdk_manager.py index 7c774ab85..78a4d955f 100644 --- a/tests/test_krisp_sdk_manager.py +++ b/tests/test_krisp_sdk_manager.py @@ -194,3 +194,7 @@ class TestSampleRateConversion: expected_rates = [8000, 16000, 24000, 32000, 44100, 48000] for rate in expected_rates: assert rate in KRISP_SAMPLE_RATES + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_langchain.py b/tests/test_langchain.py index 1a3e1fe7d..8ec8905b4 100644 --- a/tests/test_langchain.py +++ b/tests/test_langchain.py @@ -97,3 +97,7 @@ class TestLangchain(unittest.IsolatedAsyncioTestCase): self.assertEqual( context_aggregator.assistant().messages[-1]["content"], self.expected_response ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_llm_response.py b/tests/test_llm_response.py index 51296f40b..8de7dda2d 100644 --- a/tests/test_llm_response.py +++ b/tests/test_llm_response.py @@ -134,3 +134,7 @@ class TestLLMFullResponseAggregator(unittest.IsolatedAsyncioTestCase): expected_down_frames=expected_down_frames, ) assert completion_ok + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_markdown_text_filter.py b/tests/test_markdown_text_filter.py index 7f6268953..250bc685a 100644 --- a/tests/test_markdown_text_filter.py +++ b/tests/test_markdown_text_filter.py @@ -244,3 +244,7 @@ class TestMarkdownTextFilter(unittest.IsolatedAsyncioTestCase): "bold and italic", "Text filtering should be re-enabled", ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_pattern_pair_aggregator.py b/tests/test_pattern_pair_aggregator.py index f4b660feb..bcc8d18f7 100644 --- a/tests/test_pattern_pair_aggregator.py +++ b/tests/test_pattern_pair_aggregator.py @@ -192,3 +192,7 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase): # Buffer should be empty self.assertEqual(self.aggregator.text.text, "") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 4b1b57e29..dda9e583d 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -528,3 +528,7 @@ class TestPipelineTask(unittest.IsolatedAsyncioTestCase): await task.run(PipelineTaskParams(loop=asyncio.get_event_loop())) except asyncio.CancelledError: assert error_received + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_piper_tts.py b/tests/test_piper_tts.py index 8d877099c..0ce14bd85 100644 --- a/tests/test_piper_tts.py +++ b/tests/test_piper_tts.py @@ -7,6 +7,7 @@ """Tests for PiperTTSService.""" import asyncio +import unittest import aiohttp import pytest @@ -143,3 +144,7 @@ async def test_run_piper_tts_error(aiohttp_client): assert "status: 404" in up_frames[0].error, ( "ErrorFrame should contain details about the 404" ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_producer_consumer.py b/tests/test_producer_consumer.py index 4e9804c1b..0fd3f862c 100644 --- a/tests/test_producer_consumer.py +++ b/tests/test_producer_consumer.py @@ -118,3 +118,7 @@ class TestProducerConsumerProcessor(unittest.IsolatedAsyncioTestCase): frames_to_send=frames_to_send, expected_down_frames=expected_down_frames, ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_protobuf_serializer.py b/tests/test_protobuf_serializer.py index 99df3f96b..14d7d1aa7 100644 --- a/tests/test_protobuf_serializer.py +++ b/tests/test_protobuf_serializer.py @@ -38,3 +38,7 @@ class TestProtobufFrameSerializer(unittest.IsolatedAsyncioTestCase): self.assertEqual(frame.audio, audio_frame.audio) self.assertEqual(frame.sample_rate, audio_frame.sample_rate) self.assertEqual(frame.num_channels, audio_frame.num_channels) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rnnoise_cancellation.py b/tests/test_rnnoise_cancellation.py index 386dcd424..a90b4f1e9 100644 --- a/tests/test_rnnoise_cancellation.py +++ b/tests/test_rnnoise_cancellation.py @@ -171,3 +171,7 @@ class TestRNNoiseCancellation(unittest.IsolatedAsyncioTestCase): self.assertLess(mse_output, mse_input, "MSE did not improve") print("Test Passed: Noise cancellation verified.") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rnnoise_filter.py b/tests/test_rnnoise_filter.py index db3ac7825..853ea0c77 100644 --- a/tests/test_rnnoise_filter.py +++ b/tests/test_rnnoise_filter.py @@ -143,3 +143,7 @@ class TestRNNoiseFilter(unittest.IsolatedAsyncioTestCase): ) await filter.stop() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rnnoise_resampling.py b/tests/test_rnnoise_resampling.py index 060c9e802..83bf65edc 100644 --- a/tests/test_rnnoise_resampling.py +++ b/tests/test_rnnoise_resampling.py @@ -132,3 +132,7 @@ class TestRNNoiseResampling(unittest.IsolatedAsyncioTestCase): ) print("Test Passed: Resampling logic verified (with mocked RNNoise).") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_run_inference.py b/tests/test_run_inference.py index ea08445a9..eb18a5fda 100644 --- a/tests/test_run_inference.py +++ b/tests/test_run_inference.py @@ -509,3 +509,7 @@ async def test_aws_bedrock_run_inference_client_exception(): with patch.object(service._aws_session, "client", return_value=mock_context_manager): with pytest.raises(Exception, match="Bedrock API Error"): await service.run_inference(mock_context) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_simple_text_aggregator.py b/tests/test_simple_text_aggregator.py index 6baab4f26..ef51cfc49 100644 --- a/tests/test_simple_text_aggregator.py +++ b/tests/test_simple_text_aggregator.py @@ -123,3 +123,7 @@ class TestSimpleTextAggregator(unittest.IsolatedAsyncioTestCase): # flush() returns any remaining text (the "W" in this case) result = await self.aggregator.flush() assert result.text == "W" + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_skip_tags_aggregator.py b/tests/test_skip_tags_aggregator.py index 1f550198d..c7fea22c3 100644 --- a/tests/test_skip_tags_aggregator.py +++ b/tests/test_skip_tags_aggregator.py @@ -62,3 +62,7 @@ class TestSkipTagsAggregator(unittest.IsolatedAsyncioTestCase): self.assertEqual(result.text, text) self.assertEqual(self.aggregator.text.text, "") self.assertEqual(self.aggregator.text.type, "sentence") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_stt_mute_filter.py b/tests/test_stt_mute_filter.py index 39631d7e8..5682aaf22 100644 --- a/tests/test_stt_mute_filter.py +++ b/tests/test_stt_mute_filter.py @@ -326,3 +326,7 @@ class TestSTTMuteFilter(unittest.IsolatedAsyncioTestCase): frames_to_send=frames_to_send, expected_down_frames=expected_returned_frames, ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_transcript_processor.py b/tests/test_transcript_processor.py index 99e231c90..1dfdd58a3 100644 --- a/tests/test_transcript_processor.py +++ b/tests/test_transcript_processor.py @@ -792,3 +792,7 @@ class TestThoughtTranscription(unittest.IsolatedAsyncioTestCase): # Verify no updates since thought wasn't properly started self.assertEqual(len(received_updates), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_idle_controller.py b/tests/test_user_idle_controller.py index 5de665353..4b6cbe1d3 100644 --- a/tests/test_user_idle_controller.py +++ b/tests/test_user_idle_controller.py @@ -214,3 +214,7 @@ class TestUserIdleController(unittest.IsolatedAsyncioTestCase): self.assertGreater(third_count, second_count) await controller.cleanup() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_idle_processor.py b/tests/test_user_idle_processor.py index eec3abe5a..3a0169ec7 100644 --- a/tests/test_user_idle_processor.py +++ b/tests/test_user_idle_processor.py @@ -218,3 +218,7 @@ class TestUserIdleProcessor(unittest.IsolatedAsyncioTestCase): ) assert callback_called.is_set(), "Idle callback not called after bot speech" + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_mute_strategy.py b/tests/test_user_mute_strategy.py index d8261877e..07724dbfa 100644 --- a/tests/test_user_mute_strategy.py +++ b/tests/test_user_mute_strategy.py @@ -137,3 +137,7 @@ class TestFunctionCallUserMuteStrategy(unittest.IsolatedAsyncioTestCase): ) ) self.assertFalse(await strategy.process_frame(InterruptionFrame())) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_turn_controller.py b/tests/test_user_turn_controller.py index d8f642594..5362847ec 100644 --- a/tests/test_user_turn_controller.py +++ b/tests/test_user_turn_controller.py @@ -190,3 +190,7 @@ class TestUserTurnController(unittest.IsolatedAsyncioTestCase): self.assertTrue(should_start) self.assertTrue(should_stop) self.assertTrue(timeout) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_turn_processor.py b/tests/test_user_turn_processor.py index 6a3dd3ef3..ab4243cc4 100644 --- a/tests/test_user_turn_processor.py +++ b/tests/test_user_turn_processor.py @@ -152,3 +152,7 @@ class TestUserTurnProcessor(unittest.IsolatedAsyncioTestCase): self.assertTrue(should_start) self.assertTrue(should_stop) self.assertFalse(timeout) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_turn_start_strategy.py b/tests/test_user_turn_start_strategy.py index dabd4593b..2b4f7eb43 100644 --- a/tests/test_user_turn_start_strategy.py +++ b/tests/test_user_turn_start_strategy.py @@ -199,3 +199,7 @@ class TestExternalUserTurnStartStrategy(unittest.IsolatedAsyncioTestCase): await strategy.process_frame(UserStartedSpeakingFrame()) self.assertTrue(should_start) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_user_turn_stop_strategy.py b/tests/test_user_turn_stop_strategy.py index f0d336bbf..d930705fd 100644 --- a/tests/test_user_turn_stop_strategy.py +++ b/tests/test_user_turn_stop_strategy.py @@ -506,3 +506,7 @@ class TestExternalUserTurnStopStrategy(unittest.IsolatedAsyncioTestCase): await strategy.process_frame(UserStoppedSpeakingFrame()) self.assertTrue(should_start) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_utils_network.py b/tests/test_utils_network.py index 616ed896a..1f0048cc5 100644 --- a/tests/test_utils_network.py +++ b/tests/test_utils_network.py @@ -32,3 +32,7 @@ class TestUtilsNetwork(unittest.IsolatedAsyncioTestCase): assert exponential_backoff_time(attempt=4, min_wait=1, max_wait=20, multiplier=2) == 16 assert exponential_backoff_time(attempt=5, min_wait=1, max_wait=20, multiplier=2) == 20 assert exponential_backoff_time(attempt=6, min_wait=1, max_wait=20, multiplier=2) == 20 + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_utils_string.py b/tests/test_utils_string.py index 0f4844748..4afde718c 100644 --- a/tests/test_utils_string.py +++ b/tests/test_utils_string.py @@ -232,3 +232,7 @@ class TestStartEndTags(unittest.IsolatedAsyncioTestCase): ("", ""), 41, ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_vad_controller.py b/tests/test_vad_controller.py new file mode 100644 index 000000000..b649a906f --- /dev/null +++ b/tests/test_vad_controller.py @@ -0,0 +1,190 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +import unittest +from typing import List + +from pipecat.audio.vad.vad_analyzer import VADAnalyzer, VADState +from pipecat.audio.vad.vad_controller import VADController +from pipecat.frames.frames import Frame, InputAudioRawFrame, StartFrame +from pipecat.processors.frame_processor import FrameDirection + + +class MockVADAnalyzer(VADAnalyzer): + """A mock VAD analyzer that returns a configurable state.""" + + def __init__(self): + """Initialize with default QUIET state.""" + super().__init__(sample_rate=16000) + self._next_state = VADState.QUIET + + def set_next_state(self, state: VADState): + """Set the state to return on the next analyze_audio call. + + Args: + state: The VADState to return. + """ + self._next_state = state + + def num_frames_required(self) -> int: + return 512 + + def voice_confidence(self, buffer: bytes) -> float: + return 0.9 + + async def analyze_audio(self, buffer: bytes) -> VADState: + """Return the configured state.""" + return self._next_state + + +class TestVADController(unittest.IsolatedAsyncioTestCase): + async def test_speech_started_event(self): + """Test that on_speech_started event is triggered when speech begins.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + speech_started = False + + @controller.event_handler("on_speech_started") + async def on_speech_started(_controller): + nonlocal speech_started + speech_started = True + + start_frame = StartFrame(audio_in_sample_rate=16000, audio_out_sample_rate=16000) + await controller.process_frame(start_frame) + + audio_frame = InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + + # Process with QUIET state - no event should fire + analyzer.set_next_state(VADState.QUIET) + await controller.process_frame(audio_frame) + self.assertFalse(speech_started) + + # Process with SPEAKING state - event should fire + analyzer.set_next_state(VADState.SPEAKING) + await controller.process_frame(audio_frame) + self.assertTrue(speech_started) + + async def test_speech_stopped_event(self): + """Test that on_speech_stopped event is triggered when speech ends.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + speech_stopped = False + + @controller.event_handler("on_speech_stopped") + async def on_speech_stopped(_controller): + nonlocal speech_stopped + speech_stopped = True + + start_frame = StartFrame(audio_in_sample_rate=16000, audio_out_sample_rate=16000) + await controller.process_frame(start_frame) + + audio_frame = InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + + # Start speaking + analyzer.set_next_state(VADState.SPEAKING) + await controller.process_frame(audio_frame) + self.assertFalse(speech_stopped) + + # Stop speaking - event should fire + analyzer.set_next_state(VADState.QUIET) + await controller.process_frame(audio_frame) + self.assertTrue(speech_stopped) + + async def test_speech_activity_event(self): + """Test that on_speech_activity event is triggered while speaking.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + activity_count = 0 + + @controller.event_handler("on_speech_activity") + async def on_speech_activity(_controller): + nonlocal activity_count + activity_count += 1 + + start_frame = StartFrame(audio_in_sample_rate=16000, audio_out_sample_rate=16000) + await controller.process_frame(start_frame) + + audio_frame = InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + + # Activity events fire while in SPEAKING state + analyzer.set_next_state(VADState.SPEAKING) + await controller.process_frame(audio_frame) + await controller.process_frame(audio_frame) + self.assertEqual(activity_count, 2) + + async def test_push_frame_event(self): + """Test that push_frame emits on_push_frame event.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + pushed_frames: List[tuple] = [] + + @controller.event_handler("on_push_frame") + async def on_push_frame(_controller, frame: Frame, direction: FrameDirection): + pushed_frames.append((frame, direction)) + + test_frame = InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + await controller.push_frame(test_frame, FrameDirection.DOWNSTREAM) + + self.assertEqual(len(pushed_frames), 1) + self.assertEqual(pushed_frames[0][0], test_frame) + self.assertEqual(pushed_frames[0][1], FrameDirection.DOWNSTREAM) + + async def test_broadcast_frame_event(self): + """Test that broadcast_frame emits on_broadcast_frame event.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + broadcast_calls: List[tuple] = [] + + @controller.event_handler("on_broadcast_frame") + async def on_broadcast_frame(_controller, frame_cls, **kwargs): + broadcast_calls.append((frame_cls, kwargs)) + + await controller.broadcast_frame( + InputAudioRawFrame, audio=b"\x00", sample_rate=16000, num_channels=1 + ) + + self.assertEqual(len(broadcast_calls), 1) + self.assertEqual(broadcast_calls[0][0], InputAudioRawFrame) + self.assertEqual(broadcast_calls[0][1]["sample_rate"], 16000) + + async def test_no_event_on_transitional_states(self): + """Test that STARTING and STOPPING states don't trigger events.""" + analyzer = MockVADAnalyzer() + controller = VADController(analyzer) + + events_triggered = [] + + @controller.event_handler("on_speech_started") + async def on_speech_started(_controller): + events_triggered.append("started") + + @controller.event_handler("on_speech_stopped") + async def on_speech_stopped(_controller): + events_triggered.append("stopped") + + start_frame = StartFrame(audio_in_sample_rate=16000, audio_out_sample_rate=16000) + await controller.process_frame(start_frame) + + audio_frame = InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + + # STARTING is a transitional state - no event + analyzer.set_next_state(VADState.STARTING) + await controller.process_frame(audio_frame) + self.assertEqual(events_triggered, []) + + # STOPPING is a transitional state - no event + analyzer.set_next_state(VADState.STOPPING) + await controller.process_frame(audio_frame) + self.assertEqual(events_triggered, []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_vad_processor.py b/tests/test_vad_processor.py new file mode 100644 index 000000000..2acb4f29d --- /dev/null +++ b/tests/test_vad_processor.py @@ -0,0 +1,143 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +import unittest +from typing import List + +from pipecat.audio.vad.vad_analyzer import VADAnalyzer, VADState +from pipecat.frames.frames import ( + InputAudioRawFrame, + UserSpeakingFrame, + VADUserStartedSpeakingFrame, + VADUserStoppedSpeakingFrame, +) +from pipecat.processors.audio.vad_processor import VADProcessor +from pipecat.tests.utils import run_test + + +class MockVADAnalyzer(VADAnalyzer): + """A mock VAD analyzer that returns states from a predefined sequence.""" + + def __init__(self, states: List[VADState]): + super().__init__(sample_rate=16000) + self._states = list(states) + self._call_index = 0 + + def num_frames_required(self) -> int: + return 512 + + def voice_confidence(self, buffer: bytes) -> float: + return 0.9 + + async def analyze_audio(self, buffer: bytes) -> VADState: + if self._call_index < len(self._states): + state = self._states[self._call_index] + self._call_index += 1 + return state + return VADState.QUIET + + +class TestVADProcessor(unittest.IsolatedAsyncioTestCase): + def _make_audio_frame(self): + return InputAudioRawFrame(audio=b"\x00" * 1024, sample_rate=16000, num_channels=1) + + async def test_forwards_audio_frames(self): + """Test that audio frames are forwarded downstream.""" + analyzer = MockVADAnalyzer([VADState.QUIET]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame()], + expected_down_frames=[InputAudioRawFrame], + ) + + async def test_pushes_started_speaking_frame(self): + """Test that VADUserStartedSpeakingFrame is pushed when speech starts.""" + analyzer = MockVADAnalyzer([VADState.QUIET, VADState.SPEAKING]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame(), self._make_audio_frame()], + expected_down_frames=[ + InputAudioRawFrame, + VADUserStartedSpeakingFrame, + UserSpeakingFrame, + InputAudioRawFrame, + ], + ) + + async def test_pushes_stopped_speaking_frame(self): + """Test that VADUserStoppedSpeakingFrame is pushed when speech stops.""" + analyzer = MockVADAnalyzer([VADState.SPEAKING, VADState.QUIET]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame(), self._make_audio_frame()], + expected_down_frames=[ + VADUserStartedSpeakingFrame, + UserSpeakingFrame, + InputAudioRawFrame, + VADUserStoppedSpeakingFrame, + InputAudioRawFrame, + ], + ) + + async def test_pushes_user_speaking_frame(self): + """Test that UserSpeakingFrame is pushed while speaking.""" + analyzer = MockVADAnalyzer([VADState.SPEAKING, VADState.SPEAKING]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame(), self._make_audio_frame()], + expected_down_frames=[ + VADUserStartedSpeakingFrame, + UserSpeakingFrame, + InputAudioRawFrame, + UserSpeakingFrame, + InputAudioRawFrame, + ], + ) + + async def test_no_vad_frames_on_starting_state(self): + """Test that STARTING state doesn't push VAD frames.""" + analyzer = MockVADAnalyzer([VADState.STARTING]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame()], + expected_down_frames=[InputAudioRawFrame], + ) + + async def test_no_vad_frames_on_stopping_state(self): + """Test that STOPPING state doesn't push VAD frames.""" + analyzer = MockVADAnalyzer([VADState.STOPPING]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame()], + expected_down_frames=[InputAudioRawFrame], + ) + + async def test_no_vad_frames_when_quiet(self): + """Test that no VAD frames are pushed when staying quiet.""" + analyzer = MockVADAnalyzer([VADState.QUIET, VADState.QUIET]) + processor = VADProcessor(vad_analyzer=analyzer) + + await run_test( + processor, + frames_to_send=[self._make_audio_frame(), self._make_audio_frame()], + expected_down_frames=[InputAudioRawFrame, InputAudioRawFrame], + ) + + +if __name__ == "__main__": + unittest.main()