STTMuteFilter: use FunctionCallsStartedFrame and support multiple function calls
This commit is contained in:
1
changelog/3292.fixed.md
Normal file
1
changelog/3292.fixed.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
- Fixed a bug in `STTMuteFilter` where the user was not always muted during function calls, especially when there were multiple simultaneous calls.
|
||||||
@@ -21,8 +21,9 @@ from pipecat.frames.frames import (
|
|||||||
BotStartedSpeakingFrame,
|
BotStartedSpeakingFrame,
|
||||||
BotStoppedSpeakingFrame,
|
BotStoppedSpeakingFrame,
|
||||||
Frame,
|
Frame,
|
||||||
FunctionCallInProgressFrame,
|
FunctionCallCancelFrame,
|
||||||
FunctionCallResultFrame,
|
FunctionCallResultFrame,
|
||||||
|
FunctionCallsStartedFrame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InterimTranscriptionFrame,
|
InterimTranscriptionFrame,
|
||||||
InterruptionFrame,
|
InterruptionFrame,
|
||||||
@@ -116,7 +117,7 @@ class STTMuteFilter(FrameProcessor):
|
|||||||
self._config = config
|
self._config = config
|
||||||
self._first_speech_handled = False
|
self._first_speech_handled = False
|
||||||
self._bot_is_speaking = False
|
self._bot_is_speaking = False
|
||||||
self._function_call_in_progress = False
|
self._function_call_in_progress = set()
|
||||||
self._is_muted = False
|
self._is_muted = False
|
||||||
|
|
||||||
async def _handle_mute_state(self, should_mute: bool):
|
async def _handle_mute_state(self, should_mute: bool):
|
||||||
@@ -176,11 +177,12 @@ class STTMuteFilter(FrameProcessor):
|
|||||||
# Process frames to determine mute state
|
# Process frames to determine mute state
|
||||||
if isinstance(frame, StartFrame):
|
if isinstance(frame, StartFrame):
|
||||||
should_mute = await self._should_mute()
|
should_mute = await self._should_mute()
|
||||||
elif isinstance(frame, FunctionCallInProgressFrame):
|
elif isinstance(frame, FunctionCallsStartedFrame):
|
||||||
self._function_call_in_progress = True
|
for f in frame.function_calls:
|
||||||
|
self._function_call_in_progress.add(f.tool_call_id)
|
||||||
should_mute = await self._should_mute()
|
should_mute = await self._should_mute()
|
||||||
elif isinstance(frame, FunctionCallResultFrame):
|
elif isinstance(frame, (FunctionCallCancelFrame, FunctionCallResultFrame)):
|
||||||
self._function_call_in_progress = False
|
self._function_call_in_progress.remove(frame.tool_call_id)
|
||||||
should_mute = await self._should_mute()
|
should_mute = await self._should_mute()
|
||||||
elif isinstance(frame, BotStartedSpeakingFrame):
|
elif isinstance(frame, BotStartedSpeakingFrame):
|
||||||
self._bot_is_speaking = True
|
self._bot_is_speaking = True
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import unittest
|
|||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotStartedSpeakingFrame,
|
BotStartedSpeakingFrame,
|
||||||
BotStoppedSpeakingFrame,
|
BotStoppedSpeakingFrame,
|
||||||
|
FunctionCallFromLLM,
|
||||||
FunctionCallInProgressFrame,
|
FunctionCallInProgressFrame,
|
||||||
FunctionCallResultFrame,
|
FunctionCallResultFrame,
|
||||||
|
FunctionCallsStartedFrame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InterimTranscriptionFrame,
|
InterimTranscriptionFrame,
|
||||||
TranscriptionFrame,
|
TranscriptionFrame,
|
||||||
@@ -148,54 +150,59 @@ class TestSTTMuteFilter(unittest.IsolatedAsyncioTestCase):
|
|||||||
expected_down_frames=expected_returned_frames,
|
expected_down_frames=expected_returned_frames,
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Revisit once we figure out how to test SystemFrames and DataFrames
|
async def test_function_call_strategy(self):
|
||||||
# async def test_function_call_strategy(self):
|
filter = STTMuteFilter(config=STTMuteConfig(strategies={STTMuteStrategy.FUNCTION_CALL}))
|
||||||
# filter = STTMuteFilter(config=STTMuteConfig(strategies={STTMuteStrategy.FUNCTION_CALL}))
|
|
||||||
|
|
||||||
# frames_to_send = [
|
frames_to_send = [
|
||||||
# VADUserStartedSpeakingFrame(), # Should pass through initially
|
VADUserStartedSpeakingFrame(), # Should pass through initially
|
||||||
# UserStartedSpeakingFrame(), # Should pass through initially
|
UserStartedSpeakingFrame(), # Should pass through initially
|
||||||
# VADUserStoppedSpeakingFrame(),
|
VADUserStoppedSpeakingFrame(), # Should pass through initially
|
||||||
# UserStoppedSpeakingFrame(),
|
UserStoppedSpeakingFrame(), # Should pass through initially
|
||||||
# FunctionCallInProgressFrame(
|
FunctionCallsStartedFrame(
|
||||||
# function_name="get_weather",
|
function_calls=[
|
||||||
# tool_call_id="call_123",
|
FunctionCallFromLLM(
|
||||||
# arguments='{"location": "San Francisco"}',
|
function_name="get_weather",
|
||||||
# ), # Start function call
|
tool_call_id="call_123",
|
||||||
# VADUserStartedSpeakingFrame(), # Should be suppressed
|
arguments='{"location": "San Francisco"}',
|
||||||
# UserStartedSpeakingFrame(), # Should be suppressed
|
context=None,
|
||||||
# VADUserStoppedSpeakingFrame(), # Should be suppressed
|
)
|
||||||
# UserStoppedSpeakingFrame(), # Should be suppressed
|
]
|
||||||
# FunctionCallResultFrame(
|
), # Start function call
|
||||||
# function_name="get_weather",
|
VADUserStartedSpeakingFrame(), # Should be suppressed
|
||||||
# tool_call_id="call_123",
|
UserStartedSpeakingFrame(), # Should be suppressed
|
||||||
# arguments='{"location": "San Francisco"}',
|
VADUserStoppedSpeakingFrame(), # Should be suppressed
|
||||||
# result={"temperature": 22},
|
UserStoppedSpeakingFrame(), # Should be suppressed
|
||||||
# ), # End function call
|
FunctionCallResultFrame(
|
||||||
# VADUserStartedSpeakingFrame(), # Should pass through again
|
function_name="get_weather",
|
||||||
# UserStartedSpeakingFrame(), # Should pass through again
|
tool_call_id="call_123",
|
||||||
# VADUserStoppedSpeakingFrame(),
|
arguments='{"location": "San Francisco"}',
|
||||||
# UserStoppedSpeakingFrame(),
|
result={"temperature": 22},
|
||||||
# ]
|
), # End function call
|
||||||
|
SleepFrame(),
|
||||||
|
VADUserStartedSpeakingFrame(), # Should pass through again
|
||||||
|
UserStartedSpeakingFrame(), # Should pass through again
|
||||||
|
VADUserStoppedSpeakingFrame(),
|
||||||
|
UserStoppedSpeakingFrame(),
|
||||||
|
]
|
||||||
|
|
||||||
# expected_returned_frames = [
|
expected_returned_frames = [
|
||||||
# VADUserStartedSpeakingFrame,
|
VADUserStartedSpeakingFrame,
|
||||||
# UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
# VADUserStoppedSpeakingFrame,
|
VADUserStoppedSpeakingFrame,
|
||||||
# UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
# FunctionCallInProgressFrame,
|
FunctionCallsStartedFrame,
|
||||||
# FunctionCallResultFrame,
|
FunctionCallResultFrame,
|
||||||
# VADUserStartedSpeakingFrame,
|
VADUserStartedSpeakingFrame,
|
||||||
# UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
# VADUserStoppedSpeakingFrame,
|
VADUserStoppedSpeakingFrame,
|
||||||
# UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
# ]
|
]
|
||||||
|
|
||||||
# await run_test(
|
await run_test(
|
||||||
# filter,
|
filter,
|
||||||
# frames_to_send=frames_to_send,
|
frames_to_send=frames_to_send,
|
||||||
# expected_down_frames=expected_returned_frames,
|
expected_down_frames=expected_returned_frames,
|
||||||
# )
|
)
|
||||||
|
|
||||||
async def test_mute_until_first_bot_complete_strategy(self):
|
async def test_mute_until_first_bot_complete_strategy(self):
|
||||||
filter = STTMuteFilter(
|
filter = STTMuteFilter(
|
||||||
|
|||||||
Reference in New Issue
Block a user