Fix text stream frame forwarding order and transport message type.
Push LLM/TTS frames downstream before emitting product events so the pipeline keeps correct ordering, and use OutputTransportMessageFrame instead of the urgent variant. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,7 +6,7 @@ from pipecat.frames.frames import (
|
|||||||
LLMFullResponseEndFrame,
|
LLMFullResponseEndFrame,
|
||||||
LLMFullResponseStartFrame,
|
LLMFullResponseStartFrame,
|
||||||
LLMTextFrame,
|
LLMTextFrame,
|
||||||
OutputTransportMessageUrgentFrame,
|
OutputTransportMessageFrame,
|
||||||
TTSSpeakFrame,
|
TTSSpeakFrame,
|
||||||
)
|
)
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
@@ -38,24 +38,29 @@ class ProductTextStreamProcessor(FrameProcessor):
|
|||||||
await super().process_frame(frame, direction)
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, LLMFullResponseStartFrame):
|
if isinstance(frame, LLMFullResponseStartFrame):
|
||||||
|
await self.push_frame(frame, direction)
|
||||||
await self._start_turn()
|
await self._start_turn()
|
||||||
elif isinstance(frame, LLMTextFrame):
|
elif isinstance(frame, LLMTextFrame):
|
||||||
|
await self.push_frame(frame, direction)
|
||||||
if frame.text:
|
if frame.text:
|
||||||
await self._delta(frame.text)
|
await self._delta(frame.text)
|
||||||
elif isinstance(frame, LLMFullResponseEndFrame):
|
elif isinstance(frame, LLMFullResponseEndFrame):
|
||||||
|
await self.push_frame(frame, direction)
|
||||||
await self._end_turn(interrupted=False)
|
await self._end_turn(interrupted=False)
|
||||||
elif isinstance(frame, InterruptionFrame):
|
elif isinstance(frame, InterruptionFrame):
|
||||||
|
await self.push_frame(frame, direction)
|
||||||
await self._end_turn(interrupted=True)
|
await self._end_turn(interrupted=True)
|
||||||
elif isinstance(frame, TTSSpeakFrame):
|
elif isinstance(frame, TTSSpeakFrame):
|
||||||
# Fixed-text / direct-speech path: there's no LLM cycle, so
|
# Fixed-text / direct-speech path: there's no LLM cycle, so
|
||||||
# synthesize one started/delta/final sequence for the spoken text.
|
# synthesize one started/delta/final sequence for the spoken text.
|
||||||
text = frame.text or ""
|
text = frame.text or ""
|
||||||
|
await self.push_frame(frame, direction)
|
||||||
await self._start_turn()
|
await self._start_turn()
|
||||||
if text:
|
if text:
|
||||||
await self._delta(text)
|
await self._delta(text)
|
||||||
await self._end_turn(interrupted=False)
|
await self._end_turn(interrupted=False)
|
||||||
|
else:
|
||||||
await self.push_frame(frame, direction)
|
await self.push_frame(frame, direction)
|
||||||
|
|
||||||
async def _start_turn(self) -> None:
|
async def _start_turn(self) -> None:
|
||||||
if self._turn_active:
|
if self._turn_active:
|
||||||
@@ -86,7 +91,7 @@ class ProductTextStreamProcessor(FrameProcessor):
|
|||||||
|
|
||||||
async def _emit(self, event_type: str, **payload: object) -> None:
|
async def _emit(self, event_type: str, **payload: object) -> None:
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
OutputTransportMessageUrgentFrame(
|
OutputTransportMessageFrame(
|
||||||
message={"type": event_type, **payload},
|
message={"type": event_type, **payload},
|
||||||
),
|
),
|
||||||
FrameDirection.DOWNSTREAM,
|
FrameDirection.DOWNSTREAM,
|
||||||
|
|||||||
Reference in New Issue
Block a user