diff --git a/bot.py b/bot.py index 9d03524..31266f3 100644 --- a/bot.py +++ b/bot.py @@ -25,6 +25,7 @@ from pipecat.audio.vad.vad_analyzer import VADParams from pipecat.frames.frames import ( BotStartedSpeakingFrame, BotStoppedSpeakingFrame, + CancelFrame, EndFrame, EndTaskFrame, Frame, @@ -373,6 +374,8 @@ class SilenceWatchdog(FrameProcessor): self._prompts = 0 self._bot_speaking = False self._ending = False + self._stopped = False # call is closing/ended — never arm again + self._buf = "" def _cancel(self): if self._timer and not self._timer.done(): @@ -409,7 +412,19 @@ class SilenceWatchdog(FrameProcessor): async def process_frame(self, frame: Frame, direction: FrameDirection): await super().process_frame(frame, direction) - if isinstance(frame, UserStartedSpeakingFrame): + # Stop for good once the call is closing — otherwise a timer armed on the goodbye + # turn fires ~silence_secs later, after the call already ended (spurious re-prompt). + if isinstance(frame, (EndFrame, CancelFrame)): + self._stopped = True + self._cancel() + elif isinstance(frame, LLMTextFrame): + self._buf += frame.text + elif isinstance(frame, LLMFullResponseEndFrame): + if EndCallProcessor._is_closing(self._buf): + self._stopped = True + self._cancel() + self._buf = "" + elif isinstance(frame, UserStartedSpeakingFrame): self._prompts = 0 # caller engaged again — reset self._cancel() elif isinstance(frame, BotStartedSpeakingFrame): @@ -417,7 +432,9 @@ class SilenceWatchdog(FrameProcessor): self._cancel() elif isinstance(frame, BotStoppedSpeakingFrame): self._bot_speaking = False - if self._ending: + if self._stopped: + pass # call ending — don't re-arm + elif self._ending: asyncio.create_task(self._end_soon()) else: self._arm() # start counting silence once the agent finishes