Files
pipecat/src/pipecat/processors/aggregators/sentence.py
2025-06-28 13:39:45 -04:00

74 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
"""Text sentence aggregation processor for Pipecat.
This module provides a frame processor that accumulates text frames into
complete sentences, only outputting when a sentence-ending pattern is detected.
"""
from pipecat.frames.frames import EndFrame, Frame, InterimTranscriptionFrame, TextFrame
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.utils.string import match_endofsentence
class SentenceAggregator(FrameProcessor):
"""Aggregates text frames into complete sentences.
This processor accumulates incoming text frames until a sentence-ending
pattern is detected, then outputs the complete sentence as a single frame.
Useful for ensuring downstream processors receive coherent, complete sentences
rather than fragmented text.
Frame input/output:
TextFrame("Hello,") -> None
TextFrame(" world.") -> TextFrame("Hello, world.")
Doctest: FIXME to work with asyncio
>>> import asyncio
>>> async def print_frames(aggregator, frame):
... async for frame in aggregator.process_frame(frame):
... print(frame.text)
>>> aggregator = SentenceAggregator()
>>> asyncio.run(print_frames(aggregator, TextFrame("Hello,")))
>>> asyncio.run(print_frames(aggregator, TextFrame(" world.")))
Hello, world.
"""
def __init__(self):
"""Initialize the sentence aggregator.
Sets up internal state for accumulating text frames into complete sentences.
"""
super().__init__()
self._aggregation = ""
async def process_frame(self, frame: Frame, direction: FrameDirection):
"""Process incoming frames and aggregate text into complete sentences.
Args:
frame: The incoming frame to process.
direction: The direction of frame flow in the pipeline.
"""
await super().process_frame(frame, direction)
# We ignore interim description at this point.
if isinstance(frame, InterimTranscriptionFrame):
return
if isinstance(frame, TextFrame):
self._aggregation += frame.text
if match_endofsentence(self._aggregation):
await self.push_frame(TextFrame(self._aggregation))
self._aggregation = ""
elif isinstance(frame, EndFrame):
if self._aggregation:
await self.push_frame(TextFrame(self._aggregation))
await self.push_frame(frame)
else:
await self.push_frame(frame, direction)