Merge pull request #3316 from pipecat-ai/aleix/llm-user-aggreagtor-enable-interruptions
turns(user): add support for enabling/disabling interruptions
This commit is contained in:
@@ -1 +1,12 @@
|
||||
- `PipelineParams.allow_interruptions` is now deprecated, use `LLMUserAggregator`'s new parameter `user_mute_strategies` instead.
|
||||
- `PipelineParams.allow_interruptions` is now deprecated, use `LLMUserAggregator`'s new parameter `turn_start_strategies` instead. For example, to disable interruptions but still get user turns you can do:
|
||||
|
||||
```python
|
||||
context_aggregator = LLMContextAggregatorPair(
|
||||
context,
|
||||
user_params=LLMUserAggregatorParams(
|
||||
turn_start_strategies=TurnStartStrategies(
|
||||
user=[TranscriptionUserTurnStartStrategy(enable_interruptions=False)],
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
1
changelog/3316.added.md
Normal file
1
changelog/3316.added.md
Normal file
@@ -0,0 +1 @@
|
||||
- Added `enable_interruptions` constructor argument to all user turn strategies. This tells the `LLMUserAggregator` to push or not push an `InterruptionFrame`.
|
||||
1
changelog/3316.other.md
Normal file
1
changelog/3316.other.md
Normal file
@@ -0,0 +1 @@
|
||||
- Added `52-live-transcription.py` foundational example demonstrating live transcription and translation from English to Spanish. In this example, the bot is not interruptible: as the user continues speaking, English transcriptions are queued, and the bot continuously translates and speaks each queued sentence in Spanish without being interrupted by new user speech.
|
||||
140
examples/foundational/52-live-translation.py
Normal file
140
examples/foundational/52-live-translation.py
Normal file
@@ -0,0 +1,140 @@
|
||||
#
|
||||
# Copyright (c) 2024–2025, Daily
|
||||
#
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
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.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,
|
||||
LLMUserAggregatorParams,
|
||||
)
|
||||
from pipecat.runner.types import RunnerArguments
|
||||
from pipecat.runner.utils import create_transport
|
||||
from pipecat.services.cartesia.tts import CartesiaTTSService
|
||||
from pipecat.services.deepgram.stt import DeepgramSTTService
|
||||
from pipecat.services.openai.llm import OpenAILLMService
|
||||
from pipecat.transports.base_transport import BaseTransport, TransportParams
|
||||
from pipecat.transports.daily.transport import DailyParams
|
||||
from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams
|
||||
from pipecat.turns.bot import TurnAnalyzerBotTurnStartStrategy
|
||||
from pipecat.turns.turn_start_strategies import TurnStartStrategies
|
||||
from pipecat.turns.user import TranscriptionUserTurnStartStrategy
|
||||
|
||||
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.
|
||||
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)),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
|
||||
logger.info(f"Starting bot")
|
||||
|
||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||
|
||||
tts = CartesiaTTSService(
|
||||
api_key=os.getenv("CARTESIA_API_KEY"),
|
||||
voice_id="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady
|
||||
)
|
||||
|
||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a live translation assistant. Your sole purpose is to translate English text into Spanish. When you receive English text from the user, immediately translate it into natural, fluent Spanish. Do not add explanations, commentary, or extra information—only provide the Spanish translation of the text you receive.",
|
||||
},
|
||||
]
|
||||
|
||||
context = LLMContext(messages)
|
||||
|
||||
# We use the TranscriptionUserTurnStartStrategy to start a new user turn
|
||||
# every time a transcription is received. We disable interruptions, so the
|
||||
# user can continue speaking while the bot is transcribing, without
|
||||
# interrupting the bot.
|
||||
context_aggregator = LLMContextAggregatorPair(
|
||||
context,
|
||||
user_params=LLMUserAggregatorParams(
|
||||
turn_start_strategies=TurnStartStrategies(
|
||||
user=[TranscriptionUserTurnStartStrategy(enable_interruptions=False)],
|
||||
bot=[TurnAnalyzerBotTurnStartStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())],
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
pipeline = Pipeline(
|
||||
[
|
||||
transport.input(), # Transport user input
|
||||
stt, # STT
|
||||
context_aggregator.user(), # User responses
|
||||
llm, # LLM
|
||||
tts, # TTS (bot will speak the chosen language)
|
||||
transport.output(), # Transport bot output
|
||||
context_aggregator.assistant(), # Assistant spoken responses
|
||||
]
|
||||
)
|
||||
|
||||
task = PipelineTask(
|
||||
pipeline,
|
||||
params=PipelineParams(
|
||||
enable_metrics=True,
|
||||
enable_usage_metrics=True,
|
||||
),
|
||||
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
|
||||
)
|
||||
|
||||
@transport.event_handler("on_client_connected")
|
||||
async def on_client_connected(transport, client):
|
||||
logger.info(f"Client connected")
|
||||
|
||||
@transport.event_handler("on_client_disconnected")
|
||||
async def on_client_disconnected(transport, client):
|
||||
logger.info(f"Client disconnected")
|
||||
await task.cancel()
|
||||
|
||||
runner = PipelineRunner(handle_sigint=runner_args.handle_sigint)
|
||||
|
||||
await runner.run(task)
|
||||
|
||||
|
||||
async def bot(runner_args: RunnerArguments):
|
||||
"""Main bot entry point compatible with Pipecat Cloud."""
|
||||
transport = await create_transport(runner_args, transport_params)
|
||||
await run_bot(transport, runner_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pipecat.runner.run import main
|
||||
|
||||
main()
|
||||
@@ -107,7 +107,7 @@ class PipelineParams(BaseModel):
|
||||
allow_interruptions: Whether to allow pipeline interruptions.
|
||||
|
||||
.. deprecated:: 0.0.99
|
||||
Use `LLMUserAggregator`'s new `user_mute_strategies` parameter instead.
|
||||
Use `LLMUserAggregator`'s new `turn_start_strategies` parameter instead.
|
||||
|
||||
audio_in_sample_rate: Input audio sample rate in Hz.
|
||||
audio_out_sample_rate: Output audio sample rate in Hz.
|
||||
|
||||
@@ -561,8 +561,11 @@ class LLMUserAggregator(LLMContextAggregator):
|
||||
await s.reset()
|
||||
|
||||
if params.enable_user_speaking_frames:
|
||||
# TODO(aleix): These frames should really come from the top of the pipeline.
|
||||
# TODO(aleix): This frame should really come from the top of the pipeline.
|
||||
await self.broadcast_frame(UserStartedSpeakingFrame)
|
||||
|
||||
if params.enable_interruptions:
|
||||
# TODO(aleix): This frame should really come from the top of the pipeline.
|
||||
await self.broadcast_frame(InterruptionFrame)
|
||||
|
||||
await self._call_event_handler("on_user_turn_started", strategy)
|
||||
|
||||
@@ -29,14 +29,15 @@ class ExternalBotTurnStartStrategy(BaseBotTurnStartStrategy):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *, timeout: float = 0.5):
|
||||
def __init__(self, *, timeout: float = 0.5, **kwargs):
|
||||
"""Initialize the external bot turn start strategy.
|
||||
|
||||
Args:
|
||||
timeout: A short delay used internally to handle consecutive or
|
||||
slightly delayed transcriptions.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(enable_user_speaking_frames=False)
|
||||
super().__init__(enable_user_speaking_frames=False, **kwargs)
|
||||
self._timeout = timeout
|
||||
self._text = ""
|
||||
self._user_speaking = False
|
||||
|
||||
@@ -28,14 +28,15 @@ class TranscriptionBotTurnStartStrategy(BaseBotTurnStartStrategy):
|
||||
multiple or delayed transcription frames gracefully.
|
||||
"""
|
||||
|
||||
def __init__(self, *, timeout: float = 0.5):
|
||||
def __init__(self, *, timeout: float = 0.5, **kwargs):
|
||||
"""Initialize the transcription-based bot turn start strategy.
|
||||
|
||||
Args:
|
||||
timeout: A short delay used internally to handle consecutive or
|
||||
slightly delayed transcriptions.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__()
|
||||
super().__init__(**kwargs)
|
||||
self._timeout = timeout
|
||||
self._text = ""
|
||||
self._vad_user_speaking = False
|
||||
|
||||
@@ -35,14 +35,15 @@ class TurnAnalyzerBotTurnStartStrategy(BaseBotTurnStartStrategy):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *, turn_analyzer: BaseTurnAnalyzer, timeout: float = 0.5):
|
||||
def __init__(self, *, turn_analyzer: BaseTurnAnalyzer, timeout: float = 0.5, **kwargs):
|
||||
"""Initialize the bot turn start strategy.
|
||||
|
||||
Args:
|
||||
turn_analyzer: The turn detection analyzer instance to detect end of user turn.
|
||||
timeout: Short delay used internally to handle frame timing and event triggering.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__()
|
||||
super().__init__(**kwargs)
|
||||
self._turn_analyzer = turn_analyzer
|
||||
self._timeout = timeout
|
||||
self._text = ""
|
||||
|
||||
@@ -32,6 +32,7 @@ class UserTurnStartedParams:
|
||||
|
||||
"""
|
||||
|
||||
enable_interruptions: bool
|
||||
enable_user_speaking_frames: bool
|
||||
|
||||
|
||||
@@ -49,18 +50,27 @@ class BaseUserTurnStartStrategy(BaseObject):
|
||||
- `on_user_turn_started`: Signals that a user turn has started.
|
||||
"""
|
||||
|
||||
def __init__(self, *, enable_user_speaking_frames: bool = True, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
enable_interruptions: bool = True,
|
||||
enable_user_speaking_frames: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
"""Initialize the base user turn start strategy.
|
||||
|
||||
Args:
|
||||
enable_user_speaking_frames: If True, the aggregator will emit frames
|
||||
indicating when the user starts speaking, as well as interruption
|
||||
frames. This is enabled by default, but you may want to disable it
|
||||
if another component (e.g., an STT service) is already generating
|
||||
these frames.
|
||||
enable_interruptions: If True, the user aggregator will emit an
|
||||
interruption frame when the user turn starts.
|
||||
enable_user_speaking_frames: If True, the user aggregator will emit
|
||||
frames indicating when the user starts speaking, as well as
|
||||
interruption frames. This is enabled by default, but you may want
|
||||
to disable it if another component (e.g., an STT service) is
|
||||
already generating these frames.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
self._enable_interruptions = enable_interruptions
|
||||
self._enable_user_speaking_frames = enable_user_speaking_frames
|
||||
self._task_manager: Optional[BaseTaskManager] = None
|
||||
self._register_event_handler("on_push_frame", sync=True)
|
||||
@@ -123,5 +133,8 @@ class BaseUserTurnStartStrategy(BaseObject):
|
||||
"""Trigger the `on_user_turn_started` event."""
|
||||
await self._call_event_handler(
|
||||
"on_user_turn_started",
|
||||
UserTurnStartedParams(enable_user_speaking_frames=self._enable_user_speaking_frames),
|
||||
UserTurnStartedParams(
|
||||
enable_interruptions=self._enable_interruptions,
|
||||
enable_user_speaking_frames=self._enable_user_speaking_frames,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -19,9 +19,13 @@ class ExternalUserTurnStartStrategy(BaseUserTurnStartStrategy):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the external user turn start strategy."""
|
||||
super().__init__(enable_user_speaking_frames=False)
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize the external user turn start strategy.
|
||||
|
||||
Args:
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(enable_user_speaking_frames=False, **kwargs)
|
||||
|
||||
async def process_frame(self, frame: Frame):
|
||||
"""Process an incoming frame to detect user turn start.
|
||||
|
||||
@@ -27,7 +27,7 @@ class MinWordsUserTurnStartStrategy(BaseUserTurnStartStrategy):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *, min_words: int, use_interim: bool = True):
|
||||
def __init__(self, *, min_words: int, use_interim: bool = True, **kwargs):
|
||||
"""Initialize the minimum words bot turn start strategy.
|
||||
|
||||
Args:
|
||||
@@ -35,8 +35,9 @@ class MinWordsUserTurnStartStrategy(BaseUserTurnStartStrategy):
|
||||
start of a user turn.
|
||||
use_interim: Whether to consider interim transcription frames for
|
||||
earlier detection.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__()
|
||||
super().__init__(**kwargs)
|
||||
self._min_words = min_words
|
||||
self._use_interim = use_interim
|
||||
self._bot_speaking = False
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
"""User turn start strategy based on transcriptions."""
|
||||
|
||||
from pipecat.frames.frames import BotStartedSpeakingFrame, Frame, TranscriptionFrame
|
||||
from pipecat.frames.frames import Frame, InterimTranscriptionFrame, TranscriptionFrame
|
||||
from pipecat.turns.user.base_user_turn_start_strategy import BaseUserTurnStartStrategy
|
||||
|
||||
|
||||
@@ -20,15 +20,10 @@ class TranscriptionUserTurnStartStrategy(BaseUserTurnStartStrategy):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, *, use_interim: bool = True, **kwargs):
|
||||
"""Initialize transcription-based user turn start strategy."""
|
||||
super().__init__()
|
||||
self._bot_speaking = False
|
||||
|
||||
async def reset(self):
|
||||
"""Reset the strategy to its initial state."""
|
||||
await super().reset()
|
||||
self._bot_speaking = False
|
||||
super().__init__(**kwargs)
|
||||
self._use_interim = use_interim
|
||||
|
||||
async def process_frame(self, frame: Frame):
|
||||
"""Process an incoming frame to detect the start of a user turn.
|
||||
@@ -38,14 +33,7 @@ class TranscriptionUserTurnStartStrategy(BaseUserTurnStartStrategy):
|
||||
"""
|
||||
await super().process_frame(frame)
|
||||
|
||||
if isinstance(frame, BotStartedSpeakingFrame):
|
||||
await self._handle_bot_started_speaking(frame)
|
||||
elif isinstance(frame, TranscriptionFrame):
|
||||
await self._handle_transcription(frame)
|
||||
|
||||
async def _handle_bot_started_speaking(self, _: BotStartedSpeakingFrame):
|
||||
self._bot_speaking = True
|
||||
|
||||
async def _handle_transcription(self, _: TranscriptionFrame):
|
||||
if self._bot_speaking:
|
||||
if isinstance(frame, InterimTranscriptionFrame) and self._use_interim:
|
||||
await self.trigger_user_turn_started()
|
||||
elif isinstance(frame, TranscriptionFrame):
|
||||
await self.trigger_user_turn_started()
|
||||
|
||||
@@ -33,7 +33,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -58,7 +58,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -89,7 +89,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -136,7 +136,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -170,7 +170,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -212,7 +212,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -242,7 +242,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -278,7 +278,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -316,7 +316,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -350,7 +350,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -395,7 +395,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -415,7 +415,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -440,7 +440,7 @@ class TestTranscriptionBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -484,7 +484,7 @@ class TestExternalBotTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_bot_turn_started")
|
||||
async def on_bot_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_bot_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -61,7 +61,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -83,7 +83,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -104,7 +104,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -117,7 +117,7 @@ class TestMinWordsInterruptionStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -134,7 +134,7 @@ class TestVADUserTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
@@ -152,14 +152,11 @@ class TestTranscriptionUserTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
await strategy.process_frame(TranscriptionFrame(text="Hello!", user_id="", timestamp="now"))
|
||||
self.assertFalse(should_start)
|
||||
|
||||
await strategy.process_frame(BotStartedSpeakingFrame())
|
||||
await strategy.process_frame(VADUserStartedSpeakingFrame())
|
||||
self.assertFalse(should_start)
|
||||
|
||||
await strategy.process_frame(TranscriptionFrame(text="Hello!", user_id="", timestamp="now"))
|
||||
@@ -173,7 +170,7 @@ class TestExternalUserTurnStartStrategy(unittest.IsolatedAsyncioTestCase):
|
||||
should_start = None
|
||||
|
||||
@strategy.event_handler("on_user_turn_started")
|
||||
async def on_user_turn_started(strategy, enable_user_speaking_frames):
|
||||
async def on_user_turn_started(strategy, params):
|
||||
nonlocal should_start
|
||||
should_start = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user