diff --git a/src/pipecat/frames/frames.py b/src/pipecat/frames/frames.py index b535d0de0..572246c6d 100644 --- a/src/pipecat/frames/frames.py +++ b/src/pipecat/frames/frames.py @@ -241,7 +241,7 @@ class StopInterruptionFrame(SystemFrame): @dataclass class MetricsFrame(SystemFrame): - """Emitted by processor who can compute metrics like latencies. + """Emitted by processor that can compute metrics like latencies. """ ttfb: Mapping[str, float] diff --git a/src/pipecat/transports/base_output.py b/src/pipecat/transports/base_output.py index b81f2f8db..4c19a0b55 100644 --- a/src/pipecat/transports/base_output.py +++ b/src/pipecat/transports/base_output.py @@ -20,6 +20,7 @@ from pipecat.frames.frames import ( AudioRawFrame, CancelFrame, + MetricsFrame, SpriteFrame, StartFrame, EndFrame, @@ -87,6 +88,9 @@ async def stop(self): def send_message(self, frame: TransportMessageFrame): pass + def send_metrics(self, frame: MetricsFrame): + pass + def write_frame_to_camera(self, frame: ImageRawFrame): pass @@ -166,6 +170,8 @@ def _sink_thread_handler(self): self._set_camera_images(frame.images) elif isinstance(frame, TransportMessageFrame): self.send_message(frame) + elif isinstance(frame, MetricsFrame): + self.send_metrics(frame) else: future = asyncio.run_coroutine_threadsafe( self._internal_push_frame(frame), self.get_event_loop()) diff --git a/src/pipecat/transports/services/daily.py b/src/pipecat/transports/services/daily.py index 8e42a1678..0b440181c 100644 --- a/src/pipecat/transports/services/daily.py +++ b/src/pipecat/transports/services/daily.py @@ -27,6 +27,7 @@ Frame, ImageRawFrame, InterimTranscriptionFrame, + MetricsFrame, SpriteFrame, StartFrame, TranscriptionFrame, @@ -638,6 +639,16 @@ async def cleanup(self): def send_message(self, frame: DailyTransportMessageFrame): self._client.send_message(frame) + def send_metrics(self, frame: MetricsFrame): + ttfb = [{"name": n, "time": t} for n, t in frame.ttfb.items()] + message = DailyTransportMessageFrame(message={ + "type": "pipecat-metrics", + "metrics": { + "ttfb": ttfb + }, + }) + self._client.send_message(message) + def write_raw_audio_frames(self, frames: bytes): self._client.write_raw_audio_frames(frames) @@ -711,7 +722,7 @@ def output(self) -> FrameProcessor: # DailyTransport # - @property + @ property def participant_id(self) -> str: return self._client.participant_id