feat(workflow): add edge-tool routing and realtime runtime
This commit is contained in:
@@ -16,6 +16,7 @@ from models import AssistantConfig
|
||||
from openai import AsyncOpenAI
|
||||
from PIL import Image
|
||||
from services.brains import Brain, BrainRuntime, build_brain
|
||||
from services.brains.base import RealtimeBrainRuntime
|
||||
from services.conversation_history import ConversationRecorder
|
||||
from services.pipecat.call_lifecycle import (
|
||||
CallEndCoordinator,
|
||||
@@ -73,6 +74,7 @@ from services.pipecat.processors import (
|
||||
KnowledgeRetrievalProcessor,
|
||||
PassthroughLLMAssistantAggregator,
|
||||
RealtimeDynamicVariableProcessor,
|
||||
RealtimeInputAudioGateProcessor,
|
||||
RealtimeUserInputProcessor,
|
||||
SessionUpdateProcessor,
|
||||
UserInput,
|
||||
@@ -890,7 +892,32 @@ async def run_realtime_pipeline(
|
||||
instructions=brain.system_prompt(cfg),
|
||||
)
|
||||
input_sample_rate, output_sample_rate = realtime_audio_sample_rates(cfg)
|
||||
user_input = RealtimeUserInputProcessor()
|
||||
worker_holder: dict[str, PipelineWorker] = {}
|
||||
input_state = {"enabled": True}
|
||||
|
||||
async def queue_call_end(reason: str) -> None:
|
||||
worker = worker_holder.get("worker")
|
||||
if worker is None:
|
||||
return
|
||||
logger.info(f"结束 Realtime 通话: reason={reason}")
|
||||
await worker.queue_frame(
|
||||
OutputTransportMessageUrgentFrame(
|
||||
message={"type": "call-ended", "reason": reason}
|
||||
)
|
||||
)
|
||||
await worker.queue_frame(EndFrame())
|
||||
|
||||
call_end = CallEndCoordinator(queue_call_end)
|
||||
client_tools = ClientToolBroker()
|
||||
client_tools.set_interrupt_handler(realtime.interrupt)
|
||||
user_input = RealtimeUserInputProcessor(
|
||||
should_ignore_input=lambda: (
|
||||
call_end.ending or not input_state["enabled"]
|
||||
)
|
||||
)
|
||||
input_gate = RealtimeInputAudioGateProcessor(
|
||||
lambda: not call_end.ending and input_state["enabled"]
|
||||
)
|
||||
dynamic_variables = RealtimeDynamicVariableProcessor(brain, cfg, realtime)
|
||||
|
||||
async def refresh_realtime_instructions() -> None:
|
||||
@@ -910,14 +937,22 @@ async def run_realtime_pipeline(
|
||||
channel=channel,
|
||||
runtime_mode=cfg.runtimeMode,
|
||||
session_id=cfg.conversation_id or None,
|
||||
extra=(
|
||||
WorkflowEngine(cfg.graph).session_metadata()
|
||||
if cfg.type == "workflow"
|
||||
else None
|
||||
),
|
||||
)
|
||||
pipeline = Pipeline(
|
||||
[
|
||||
transport.input(),
|
||||
client_tools,
|
||||
session_update,
|
||||
user_input,
|
||||
input_gate,
|
||||
realtime,
|
||||
dynamic_variables,
|
||||
EndCallAfterSpeechProcessor(call_end),
|
||||
ConversationHistoryProcessor(recorder),
|
||||
transport.output(),
|
||||
]
|
||||
@@ -931,11 +966,28 @@ async def run_realtime_pipeline(
|
||||
),
|
||||
enable_rtvi=False,
|
||||
)
|
||||
worker_holder["worker"] = worker
|
||||
|
||||
def set_input_enabled(enabled: bool) -> None:
|
||||
input_state["enabled"] = enabled
|
||||
|
||||
await brain.setup_realtime(
|
||||
cfg,
|
||||
RealtimeBrainRuntime(
|
||||
realtime=realtime,
|
||||
queue_frame=worker.queue_frame,
|
||||
call_end=call_end,
|
||||
session_id=cfg.conversation_id or "",
|
||||
client_tools=client_tools,
|
||||
set_input_enabled=set_input_enabled,
|
||||
),
|
||||
)
|
||||
|
||||
bind_realtime_pipeline_events(
|
||||
transport=transport,
|
||||
worker=worker,
|
||||
realtime=realtime,
|
||||
brain=brain,
|
||||
text_input=user_input,
|
||||
greeting=greeting,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user