Initial commit of current state
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
"""Stop the agent from hearing itself.
|
||||
|
||||
On laptop speakers with no acoustic echo cancellation, the microphone picks up
|
||||
whatever Kokoro just said. The recognizer transcribes it, the aggregator treats
|
||||
it as a user turn, and the agent answers its own greeting — which is exactly
|
||||
what happens without this.
|
||||
|
||||
Pipecat's ``AlwaysUserMuteStrategy`` mutes while the bot is speaking, but
|
||||
unmutes the instant playback ends, and the tail of that audio is still in the
|
||||
input buffer. This keeps the mute up for a short while afterwards.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame
|
||||
from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
|
||||
|
||||
|
||||
class EchoGuardUserMuteStrategy(BaseUserMuteStrategy):
|
||||
"""Mute the user while the bot speaks, plus a tail to let echo drain.
|
||||
|
||||
Args:
|
||||
tail_secs: How long to stay muted after playback ends.
|
||||
"""
|
||||
|
||||
def __init__(self, *, tail_secs: float = 0.4):
|
||||
super().__init__()
|
||||
self._tail_secs = tail_secs
|
||||
self._bot_speaking = False
|
||||
self._stopped_at = 0.0
|
||||
|
||||
async def process_frame(self, frame: Frame) -> bool:
|
||||
await super().process_frame(frame)
|
||||
|
||||
if isinstance(frame, BotStartedSpeakingFrame):
|
||||
self._bot_speaking = True
|
||||
elif isinstance(frame, BotStoppedSpeakingFrame):
|
||||
self._bot_speaking = False
|
||||
self._stopped_at = time.monotonic()
|
||||
|
||||
if self._bot_speaking:
|
||||
return True
|
||||
return time.monotonic() - self._stopped_at < self._tail_secs
|
||||
Reference in New Issue
Block a user