Merge pull request #3479 from pipecat-ai/aleix/turns-mute-to-user-mute

turns: move mute to user_mute
This commit is contained in:
Aleix Conchillo Flaqué
2026-01-16 11:11:50 -08:00
committed by GitHub
15 changed files with 72 additions and 218 deletions

View File

@@ -0,0 +1 @@
- For consistency with other package names, we just deprecated `pipecat.turns.mute` (introduced in Pipecat 0.0.99) in favor of `pipecat.turns.user_mute`.

View File

@@ -1,182 +0,0 @@
#
# Copyright (c) 2024-2026, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
import asyncio
import os
from dotenv import load_dotenv
from loguru import logger
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 LLMRunFrame
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.processors.filters.stt_mute_filter import STTMuteConfig, STTMuteFilter, STTMuteStrategy
from pipecat.runner.types import RunnerArguments
from pipecat.runner.utils import create_transport
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.deepgram.tts import DeepgramTTSService
from pipecat.services.llm_service import FunctionCallParams
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.user_stop import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies
load_dotenv(override=True)
async def fetch_weather_from_api(params: FunctionCallParams):
# Add a delay to test interruption during function calls
logger.info("Weather API call starting...")
await asyncio.sleep(5) # 5-second delay
logger.info("Weather API call completed")
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.
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"))
# Configure the mute processor with both strategies
stt_mute_processor = STTMuteFilter(
config=STTMuteConfig(
strategies={
STTMuteStrategy.MUTE_UNTIL_FIRST_BOT_COMPLETE,
STTMuteStrategy.FUNCTION_CALL,
}
),
)
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
llm.register_function("get_current_weather", fetch_weather_from_api)
weather_function = FunctionSchema(
name="get_current_weather",
description="Get the current weather",
properties={
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the user's location.",
},
},
required=["location", "format"],
)
tools = ToolsSchema(standard_tools=[weather_function])
messages = [
{
"role": "system",
"content": "You are a helpful assistant who can check the weather. Always check the weather when a location is mentioned. Respond concisely and naturally. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points.",
},
]
context = LLMContext(messages, tools)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
context,
user_params=LLMUserAggregatorParams(
user_turn_strategies=UserTurnStrategies(
stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())]
),
),
)
pipeline = Pipeline(
[
transport.input(), # Transport user input
stt, # STT
stt_mute_processor, # Add the mute processor between STT and context aggregator
user_aggregator, # User responses
llm, # LLM
tts, # TTS
transport.output(), # Transport bot output
assistant_aggregator, # 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")
# Kick off the conversation with a weather-related prompt
messages.append(
{
"role": "system",
"content": "Ask the user what city they'd like to know the weather for.",
}
)
await task.queue_frames([LLMRunFrame()])
@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()

View File

@@ -34,7 +34,7 @@ from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.base_transport import BaseTransport, TransportParams
from pipecat.transports.daily.transport import DailyParams from pipecat.transports.daily.transport import DailyParams
from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams
from pipecat.turns.mute import ( from pipecat.turns.user_mute import (
FunctionCallUserMuteStrategy, FunctionCallUserMuteStrategy,
MuteUntilFirstBotCompleteUserMuteStrategy, MuteUntilFirstBotCompleteUserMuteStrategy,
) )

View File

@@ -62,7 +62,7 @@ from pipecat.processors.aggregators.llm_context import (
NotGiven, NotGiven,
) )
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.turns.mute import BaseUserMuteStrategy from pipecat.turns.user_mute import BaseUserMuteStrategy
from pipecat.turns.user_start import BaseUserTurnStartStrategy, UserTurnStartedParams from pipecat.turns.user_start import BaseUserTurnStartStrategy, UserTurnStartedParams
from pipecat.turns.user_stop import BaseUserTurnStopStrategy, UserTurnStoppedParams from pipecat.turns.user_stop import BaseUserTurnStopStrategy, UserTurnStoppedParams
from pipecat.turns.user_turn_controller import UserTurnController from pipecat.turns.user_turn_controller import UserTurnController

View File

@@ -4,10 +4,21 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
from pipecat.turns.mute.always_user_mute_strategy import AlwaysUserMuteStrategy import warnings
from pipecat.turns.mute.base_user_mute_strategy import BaseUserMuteStrategy
from pipecat.turns.mute.first_speech_user_mute_strategy import FirstSpeechUserMuteStrategy from pipecat.turns.user_mute.always_user_mute_strategy import AlwaysUserMuteStrategy
from pipecat.turns.mute.function_call_user_mute_strategy import FunctionCallUserMuteStrategy from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
from pipecat.turns.mute.mute_until_first_bot_complete_user_mute_strategy import ( from pipecat.turns.user_mute.first_speech_user_mute_strategy import FirstSpeechUserMuteStrategy
from pipecat.turns.user_mute.function_call_user_mute_strategy import FunctionCallUserMuteStrategy
from pipecat.turns.user_mute.mute_until_first_bot_complete_user_mute_strategy import (
MuteUntilFirstBotCompleteUserMuteStrategy, MuteUntilFirstBotCompleteUserMuteStrategy,
) )
with warnings.catch_warnings():
warnings.simplefilter("always")
warnings.warn(
"Types in pipecat.turns.mute are deprecated. "
"Please use the equivalent types from pipecat.turns.user_mute instead.",
DeprecationWarning,
stacklevel=2,
)

View File

@@ -0,0 +1,21 @@
#
# Copyright (c) 2024-2026, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
from .always_user_mute_strategy import AlwaysUserMuteStrategy
from .base_user_mute_strategy import BaseUserMuteStrategy
from .first_speech_user_mute_strategy import FirstSpeechUserMuteStrategy
from .function_call_user_mute_strategy import FunctionCallUserMuteStrategy
from .mute_until_first_bot_complete_user_mute_strategy import (
MuteUntilFirstBotCompleteUserMuteStrategy,
)
__all__ = [
"AlwaysUserMuteStrategy",
"BaseUserMuteStrategy",
"FirstSpeechUserMuteStrategy",
"FunctionCallUserMuteStrategy",
"MuteUntilFirstBotCompleteUserMuteStrategy",
]

View File

@@ -7,7 +7,7 @@
"""User mute strategy that always mutes the user while the bot is speaking.""" """User mute strategy that always mutes the user while the bot is speaking."""
from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame
from pipecat.turns.mute.base_user_mute_strategy import BaseUserMuteStrategy from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
class AlwaysUserMuteStrategy(BaseUserMuteStrategy): class AlwaysUserMuteStrategy(BaseUserMuteStrategy):

View File

@@ -7,7 +7,7 @@
"""User mute strategy that mutes the user only during the bots first speech.""" """User mute strategy that mutes the user only during the bots first speech."""
from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame
from pipecat.turns.mute.base_user_mute_strategy import BaseUserMuteStrategy from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
class FirstSpeechUserMuteStrategy(BaseUserMuteStrategy): class FirstSpeechUserMuteStrategy(BaseUserMuteStrategy):

View File

@@ -14,7 +14,7 @@ from pipecat.frames.frames import (
FunctionCallResultFrame, FunctionCallResultFrame,
FunctionCallsStartedFrame, FunctionCallsStartedFrame,
) )
from pipecat.turns.mute.base_user_mute_strategy import BaseUserMuteStrategy from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
class FunctionCallUserMuteStrategy(BaseUserMuteStrategy): class FunctionCallUserMuteStrategy(BaseUserMuteStrategy):

View File

@@ -7,7 +7,7 @@
"""User mute strategy that mutes the user until the bot completes its first speech.""" """User mute strategy that mutes the user until the bot completes its first speech."""
from pipecat.frames.frames import BotStoppedSpeakingFrame, Frame from pipecat.frames.frames import BotStoppedSpeakingFrame, Frame
from pipecat.turns.mute.base_user_mute_strategy import BaseUserMuteStrategy from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
class MuteUntilFirstBotCompleteUserMuteStrategy(BaseUserMuteStrategy): class MuteUntilFirstBotCompleteUserMuteStrategy(BaseUserMuteStrategy):

View File

@@ -4,15 +4,17 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
from pipecat.turns.user_start.base_user_turn_start_strategy import ( from .base_user_turn_start_strategy import BaseUserTurnStartStrategy, UserTurnStartedParams
BaseUserTurnStartStrategy, from .external_user_turn_start_strategy import ExternalUserTurnStartStrategy
UserTurnStartedParams, from .min_words_user_turn_start_strategy import MinWordsUserTurnStartStrategy
) from .transcription_user_turn_start_strategy import TranscriptionUserTurnStartStrategy
from pipecat.turns.user_start.external_user_turn_start_strategy import ExternalUserTurnStartStrategy from .vad_user_turn_start_strategy import VADUserTurnStartStrategy
from pipecat.turns.user_start.min_words_user_turn_start_strategy import (
MinWordsUserTurnStartStrategy, __all__ = [
) "BaseUserTurnStartStrategy",
from pipecat.turns.user_start.transcription_user_turn_start_strategy import ( "ExternalUserTurnStartStrategy",
TranscriptionUserTurnStartStrategy, "MinWordsUserTurnStartStrategy",
) "TranscriptionUserTurnStartStrategy",
from pipecat.turns.user_start.vad_user_turn_start_strategy import VADUserTurnStartStrategy "UserTurnStartedParams",
"VADUserTurnStartStrategy",
]

View File

@@ -4,14 +4,15 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
from pipecat.turns.user_stop.base_user_turn_stop_strategy import ( from .base_user_turn_stop_strategy import BaseUserTurnStopStrategy, UserTurnStoppedParams
BaseUserTurnStopStrategy, from .external_user_turn_stop_strategy import ExternalUserTurnStopStrategy
UserTurnStoppedParams, from .transcription_user_turn_stop_strategy import TranscriptionUserTurnStopStrategy
) from .turn_analyzer_user_turn_stop_strategy import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_stop.external_user_turn_stop_strategy import ExternalUserTurnStopStrategy
from pipecat.turns.user_stop.transcription_user_turn_stop_strategy import ( __all__ = [
TranscriptionUserTurnStopStrategy, "BaseUserTurnStopStrategy",
) "ExternalUserTurnStopStrategy",
from pipecat.turns.user_stop.turn_analyzer_user_turn_stop_strategy import ( "UserTurnStoppedParams",
TurnAnalyzerUserTurnStopStrategy, "TranscriptionUserTurnStopStrategy",
) "TurnAnalyzerUserTurnStopStrategy",
]

View File

@@ -40,7 +40,7 @@ from pipecat.processors.aggregators.llm_response_universal import (
LLMUserAggregatorParams, LLMUserAggregatorParams,
) )
from pipecat.tests.utils import SleepFrame, run_test from pipecat.tests.utils import SleepFrame, run_test
from pipecat.turns.mute import FirstSpeechUserMuteStrategy, FunctionCallUserMuteStrategy from pipecat.turns.user_mute import FirstSpeechUserMuteStrategy, FunctionCallUserMuteStrategy
from pipecat.turns.user_stop import TranscriptionUserTurnStopStrategy from pipecat.turns.user_stop import TranscriptionUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies from pipecat.turns.user_turn_strategies import UserTurnStrategies

View File

@@ -15,7 +15,7 @@ from pipecat.frames.frames import (
FunctionCallsStartedFrame, FunctionCallsStartedFrame,
InterruptionFrame, InterruptionFrame,
) )
from pipecat.turns.mute import ( from pipecat.turns.user_mute import (
AlwaysUserMuteStrategy, AlwaysUserMuteStrategy,
FirstSpeechUserMuteStrategy, FirstSpeechUserMuteStrategy,
FunctionCallUserMuteStrategy, FunctionCallUserMuteStrategy,