fix(realtime): complete workflow message transitions
This commit is contained in:
@@ -21,6 +21,7 @@ from pipecat.frames.frames import (
|
||||
OutputTransportMessageUrgentFrame,
|
||||
StartFrame,
|
||||
TTSAudioRawFrame,
|
||||
TTSStoppedFrame,
|
||||
)
|
||||
from pipecat.processors.frame_processor import FrameDirection
|
||||
from pipecat.services.ai_service import AIService
|
||||
@@ -85,6 +86,7 @@ class StepFunRealtimeService(AIService):
|
||||
)
|
||||
self._fixed_speech_completion: asyncio.Future[None] | None = None
|
||||
self._fixed_speech_request_item_id: str | None = None
|
||||
self._entry_trigger_item_id: str | None = None
|
||||
self._suppress_response_transcript = False
|
||||
self._speech_started_handler: SpeechStartedHandler | None = None
|
||||
self._function_names: dict[str, str] = {}
|
||||
@@ -164,9 +166,27 @@ class StepFunRealtimeService(AIService):
|
||||
self._resolve_fixed_speech()
|
||||
await self.broadcast_interruption()
|
||||
|
||||
async def request_response(self) -> None:
|
||||
async def request_response(self, *, trigger_text: str | None = None) -> None:
|
||||
if trigger_text:
|
||||
item_id = f"item_{uuid4().hex}"
|
||||
self._entry_trigger_item_id = item_id
|
||||
await self._send_event(
|
||||
{
|
||||
"type": "conversation.item.create",
|
||||
"item": {
|
||||
"id": item_id,
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": trigger_text}],
|
||||
},
|
||||
}
|
||||
)
|
||||
await self._send_event({"type": "response.create"})
|
||||
|
||||
async def wait_for_response_boundary(self) -> None:
|
||||
"""Wait until StepFun has finished or cancelled the current response."""
|
||||
await self._response_done.wait()
|
||||
|
||||
def set_speech_started_handler(
|
||||
self,
|
||||
handler: SpeechStartedHandler | None,
|
||||
@@ -246,6 +266,7 @@ class StepFunRealtimeService(AIService):
|
||||
self._tool_session.clear()
|
||||
self._function_names.clear()
|
||||
self._fixed_speech_request_item_id = None
|
||||
self._entry_trigger_item_id = None
|
||||
self._resolve_fixed_speech()
|
||||
if websocket and websocket.state is State.OPEN:
|
||||
try:
|
||||
@@ -280,6 +301,7 @@ class StepFunRealtimeService(AIService):
|
||||
self._session_ready.clear()
|
||||
self._response_done.set()
|
||||
self._fixed_speech_request_item_id = None
|
||||
self._entry_trigger_item_id = None
|
||||
self._resolve_fixed_speech()
|
||||
if self._receive_task is asyncio.current_task():
|
||||
self._receive_task = None
|
||||
@@ -331,8 +353,10 @@ class StepFunRealtimeService(AIService):
|
||||
"incomplete",
|
||||
"interrupted",
|
||||
}
|
||||
await self.push_frame(TTSStoppedFrame())
|
||||
await self._finish_assistant_text(interrupted=interrupted)
|
||||
await self._delete_fixed_speech_request()
|
||||
await self._delete_entry_trigger()
|
||||
self._resolve_fixed_speech()
|
||||
self._response_done.set()
|
||||
elif event_type == "response.output_item.added":
|
||||
@@ -474,9 +498,22 @@ class StepFunRealtimeService(AIService):
|
||||
wait_until_ready=False,
|
||||
)
|
||||
|
||||
async def _delete_entry_trigger(self) -> None:
|
||||
item_id = self._entry_trigger_item_id
|
||||
self._entry_trigger_item_id = None
|
||||
if item_id:
|
||||
await self._send_event(
|
||||
{"type": "conversation.item.delete", "item_id": item_id},
|
||||
wait_until_ready=False,
|
||||
)
|
||||
|
||||
async def _send_event(
|
||||
self, payload: dict[str, Any], *, wait_until_ready: bool = True
|
||||
) -> None:
|
||||
if payload.get("type") == "response.create":
|
||||
# Mark the response busy before the server's response.created
|
||||
# arrives so an immediate confirmation cannot pass the boundary.
|
||||
self._response_done.clear()
|
||||
if wait_until_ready and not self._session_ready.is_set():
|
||||
self._pending_events.append(payload)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user