- Introduce greeting context handling in BaseBrain and WorkflowBrain to manage assistant greetings effectively. - Implement prepare_greeting_context method to add greeting messages to the local context while preserving playback order. - Update pipeline event handling to ensure greeting timestamps are maintained until the client is ready. - Enhance tests to verify the correct behavior of greeting context management in various scenarios.
109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
from unittest.mock import patch
|
|
|
|
from pipecat.frames.frames import OutputTransportMessageUrgentFrame
|
|
from services.pipecat.pipeline_events import bind_cascade_pipeline_events
|
|
|
|
|
|
class _EventSource:
|
|
def __init__(self):
|
|
self.handlers = {}
|
|
|
|
def event_handler(self, name):
|
|
def decorator(handler):
|
|
self.handlers[name] = handler
|
|
return handler
|
|
|
|
return decorator
|
|
|
|
|
|
class _Worker:
|
|
def __init__(self):
|
|
self.frames = []
|
|
|
|
async def queue_frame(self, frame):
|
|
self.frames.append(frame)
|
|
|
|
|
|
class _Brain:
|
|
spec = SimpleNamespace(owns_context=True)
|
|
|
|
def __init__(self, worker):
|
|
self.worker = worker
|
|
self.prepared_greeting = ""
|
|
|
|
def prepare_greeting_context(self, greeting, _context):
|
|
self.prepared_greeting = greeting
|
|
|
|
async def on_connected(self):
|
|
pass
|
|
|
|
async def on_client_ready(self):
|
|
for content, timestamp in (
|
|
("Start Edge 过渡语", "2026-07-14T10:00:00.200+00:00"),
|
|
("Agent 固定进入语", "2026-07-14T10:00:00.300+00:00"),
|
|
):
|
|
await self.worker.queue_frame(
|
|
OutputTransportMessageUrgentFrame(
|
|
message={
|
|
"type": "transcript",
|
|
"role": "assistant",
|
|
"content": content,
|
|
"timestamp": timestamp,
|
|
}
|
|
)
|
|
)
|
|
|
|
|
|
class PipelineEventTest(unittest.IsolatedAsyncioTestCase):
|
|
async def test_greeting_keeps_playback_timestamp_until_client_ready(self):
|
|
transport = _EventSource()
|
|
text_input = _EventSource()
|
|
user_aggregator = _EventSource()
|
|
assistant_aggregator = _EventSource()
|
|
worker = _Worker()
|
|
brain = _Brain(worker)
|
|
|
|
bind_cascade_pipeline_events(
|
|
transport=transport,
|
|
worker=worker,
|
|
brain=brain,
|
|
context=SimpleNamespace(),
|
|
text_input=text_input,
|
|
user_aggregator=user_aggregator,
|
|
assistant_aggregator=assistant_aggregator,
|
|
greeting="助手开场白",
|
|
vision_enabled=False,
|
|
vision_state={"client_id": None},
|
|
)
|
|
|
|
greeting_time = "2026-07-14T10:00:00.100+00:00"
|
|
with patch(
|
|
"services.pipecat.pipeline_events.time_now_iso8601",
|
|
return_value=greeting_time,
|
|
) as clock:
|
|
await transport.handlers["on_client_connected"](transport, object())
|
|
await text_input.handlers["on_client_ready"](text_input)
|
|
|
|
transcripts = [
|
|
frame.message
|
|
for frame in worker.frames
|
|
if isinstance(frame, OutputTransportMessageUrgentFrame)
|
|
and frame.message.get("type") == "transcript"
|
|
]
|
|
ordered = sorted(transcripts, key=lambda message: message["timestamp"])
|
|
self.assertEqual(
|
|
[message["content"] for message in ordered],
|
|
["助手开场白", "Start Edge 过渡语", "Agent 固定进入语"],
|
|
)
|
|
self.assertEqual(transcripts[0]["timestamp"], greeting_time)
|
|
self.assertEqual(brain.prepared_greeting, "助手开场白")
|
|
clock.assert_called_once_with()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|