Refactor workflow routing and greeting management in Brain classes
- Update WorkflowBrain to handle greeting playback more effectively, ensuring that the initial greeting completes before transitioning to the first node. - Introduce new methods for managing greeting states and conditions, enhancing the interaction flow for user turns. - Refactor WorkflowLLMRouter to improve routing logic and ensure proper handling of conditional paths. - Enhance tests to verify the correct behavior of greeting management and routing under various scenarios, including waiting for audio playback to finish. - Update frontend components to reflect changes in edge handling and improve user experience in workflow configurations.
This commit is contained in:
@@ -4,7 +4,11 @@ import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from pipecat.frames.frames import OutputTransportMessageUrgentFrame
|
||||
from pipecat.frames.frames import (
|
||||
BotStartedSpeakingFrame,
|
||||
BotStoppedSpeakingFrame,
|
||||
OutputTransportMessageUrgentFrame,
|
||||
)
|
||||
from services.pipecat.pipeline_events import bind_cascade_pipeline_events
|
||||
|
||||
|
||||
@@ -23,6 +27,18 @@ class _EventSource:
|
||||
class _Worker:
|
||||
def __init__(self):
|
||||
self.frames = []
|
||||
self.handlers = {}
|
||||
self.downstream_types = set()
|
||||
|
||||
def add_reached_downstream_filter(self, types):
|
||||
self.downstream_types.update(types)
|
||||
|
||||
def event_handler(self, name):
|
||||
def decorator(handler):
|
||||
self.handlers[name] = handler
|
||||
return handler
|
||||
|
||||
return decorator
|
||||
|
||||
async def queue_frame(self, frame):
|
||||
self.frames.append(frame)
|
||||
@@ -34,12 +50,17 @@ class _Brain:
|
||||
def __init__(self, worker):
|
||||
self.worker = worker
|
||||
self.prepared_greeting = ""
|
||||
self.greeting_pending = False
|
||||
self.greeting_finished = 0
|
||||
|
||||
def prepare_greeting_context(self, greeting, _context):
|
||||
self.prepared_greeting = greeting
|
||||
|
||||
async def on_connected(self):
|
||||
pass
|
||||
async def on_connected(self, *, greeting_pending=False):
|
||||
self.greeting_pending = greeting_pending
|
||||
|
||||
async def on_greeting_finished(self):
|
||||
self.greeting_finished += 1
|
||||
|
||||
async def on_client_ready(self):
|
||||
for content, timestamp in (
|
||||
@@ -101,8 +122,46 @@ class PipelineEventTest(unittest.IsolatedAsyncioTestCase):
|
||||
)
|
||||
self.assertEqual(transcripts[0]["timestamp"], greeting_time)
|
||||
self.assertEqual(brain.prepared_greeting, "助手开场白")
|
||||
self.assertTrue(brain.greeting_pending)
|
||||
clock.assert_called_once_with()
|
||||
|
||||
async def test_greeting_releases_workflow_only_after_real_playback_stop(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},
|
||||
)
|
||||
|
||||
await transport.handlers["on_client_connected"](transport, object())
|
||||
playback_handler = worker.handlers["on_frame_reached_downstream"]
|
||||
|
||||
# An unrelated stop cannot release startup until this greeting has
|
||||
# actually produced audio.
|
||||
await playback_handler(worker, BotStoppedSpeakingFrame())
|
||||
self.assertEqual(brain.greeting_finished, 0)
|
||||
|
||||
await playback_handler(worker, BotStartedSpeakingFrame())
|
||||
await playback_handler(worker, BotStoppedSpeakingFrame())
|
||||
self.assertEqual(brain.greeting_finished, 1)
|
||||
|
||||
# Duplicate transport notifications are harmless.
|
||||
await playback_handler(worker, BotStoppedSpeakingFrame())
|
||||
self.assertEqual(brain.greeting_finished, 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user