Make end call tool can be cancelled
This commit is contained in:
@@ -230,9 +230,14 @@ def message_text(message: dict) -> str:
|
||||
class UserInputProcessor(FrameProcessor):
|
||||
"""Validate app inputs and coordinate their interruption boundary."""
|
||||
|
||||
def __init__(self, should_ignore_input: Callable[[], bool] | None = None):
|
||||
def __init__(
|
||||
self,
|
||||
should_ignore_input: Callable[[], bool] | None = None,
|
||||
cancel_pending_end: Callable[[], bool] | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self._should_ignore_input = should_ignore_input or (lambda: False)
|
||||
self._cancel_pending_end = cancel_pending_end or (lambda: False)
|
||||
self._register_event_handler("on_user_input")
|
||||
self._register_event_handler("on_client_ready")
|
||||
|
||||
@@ -256,6 +261,9 @@ class UserInputProcessor(FrameProcessor):
|
||||
await self.push_frame(frame, direction)
|
||||
return
|
||||
|
||||
if user_input.run_immediately and user_input.interrupt:
|
||||
self._cancel_pending_end()
|
||||
|
||||
if self._should_ignore_input():
|
||||
logger.debug("当前会话输入已暂停,忽略用户输入")
|
||||
await self._emit_result(
|
||||
@@ -371,15 +379,25 @@ class SessionUpdateProcessor(FrameProcessor):
|
||||
|
||||
|
||||
class CallEndingUserMuteStrategy(BaseUserMuteStrategy):
|
||||
"""Keep user media muted after an end-call tool starts terminating a call."""
|
||||
"""Mute committed endings and cancel interruptible ones on user activity."""
|
||||
|
||||
def __init__(self, is_call_ending: Callable[[], bool]):
|
||||
def __init__(
|
||||
self,
|
||||
should_mute: Callable[[], bool],
|
||||
*,
|
||||
is_user_interruption: Callable[[object], bool] | None = None,
|
||||
cancel_pending_end: Callable[[], bool] | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self._is_call_ending = is_call_ending
|
||||
self._should_mute = should_mute
|
||||
self._is_user_interruption = is_user_interruption or (lambda _frame: False)
|
||||
self._cancel_pending_end = cancel_pending_end or (lambda: False)
|
||||
|
||||
async def process_frame(self, frame) -> bool:
|
||||
await super().process_frame(frame)
|
||||
return self._is_call_ending()
|
||||
if self._is_user_interruption(frame):
|
||||
self._cancel_pending_end()
|
||||
return self._should_mute()
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -570,9 +588,14 @@ class RealtimeInputAudioGateProcessor(FrameProcessor):
|
||||
class RealtimeUserInputProcessor(FrameProcessor):
|
||||
"""Route text-only user-input messages to a realtime service."""
|
||||
|
||||
def __init__(self, should_ignore_input: Callable[[], bool] | None = None):
|
||||
def __init__(
|
||||
self,
|
||||
should_ignore_input: Callable[[], bool] | None = None,
|
||||
cancel_pending_end: Callable[[], bool] | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self._should_ignore_input = should_ignore_input or (lambda: False)
|
||||
self._cancel_pending_end = cancel_pending_end or (lambda: False)
|
||||
self._register_event_handler("on_user_input")
|
||||
|
||||
async def process_frame(self, frame, direction: FrameDirection):
|
||||
@@ -590,6 +613,8 @@ class RealtimeUserInputProcessor(FrameProcessor):
|
||||
if user_input is None:
|
||||
await self.push_frame(frame, direction)
|
||||
return
|
||||
if user_input.run_immediately and user_input.interrupt:
|
||||
self._cancel_pending_end()
|
||||
if self._should_ignore_input():
|
||||
await self._emit_error(
|
||||
user_input.input_id,
|
||||
|
||||
Reference in New Issue
Block a user