From 6ef7f6446a2303ced4868eefa7c082a211bb92d6 Mon Sep 17 00:00:00 2001 From: filipi87 Date: Thu, 21 May 2026 09:01:12 -0300 Subject: [PATCH] Saving the audio inside the Tavus video so we can test. --- scripts/daily/test_tavus_transport.py | 2 +- src/pipecat/services/tavus/video.py | 30 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/scripts/daily/test_tavus_transport.py b/scripts/daily/test_tavus_transport.py index 6f542ef63..a283e043a 100644 --- a/scripts/daily/test_tavus_transport.py +++ b/scripts/daily/test_tavus_transport.py @@ -78,7 +78,7 @@ class DailyProxyApp(EventHandler): def _open_wav(self): os.makedirs("recordings", exist_ok=True) timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") - path = f"recordings/received_{timestamp}.wav" + path = f"recordings/received_pos_speed_{timestamp}.wav" self._wav_io = open(path, "wb") self._wav_file = wave.open(self._wav_io, "wb") self._wav_file.setnchannels(1) diff --git a/src/pipecat/services/tavus/video.py b/src/pipecat/services/tavus/video.py index a12b91f3b..23d741797 100644 --- a/src/pipecat/services/tavus/video.py +++ b/src/pipecat/services/tavus/video.py @@ -11,6 +11,10 @@ avatar functionality through Tavus's streaming API. """ import asyncio +import datetime +import io +import os +import wave from dataclasses import dataclass import aiohttp @@ -103,6 +107,8 @@ class TavusVideoService(AIService): # This is the custom track destination expected by Tavus self._transport_destination: str | None = "stream" self._transport_ready = False + self._wav_file: wave.Wave_write | None = None + self._wav_io: io.FileIO | None = None async def setup(self, setup: FrameProcessorSetup): """Set up the Tavus video service. @@ -204,6 +210,25 @@ class TavusVideoService(AIService): """ return await self._client.get_persona_name() + def _open_wav(self, sample_rate: int): + os.makedirs("recordings", exist_ok=True) + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + path = f"recordings/bot_pre_speed_{timestamp}.wav" + self._wav_io = open(path, "wb") + self._wav_file = wave.open(self._wav_io, "wb") + self._wav_file.setnchannels(1) + self._wav_file.setsampwidth(2) + self._wav_file.setframerate(sample_rate) + logger.info(f"Recording outgoing audio to {path}") + + def _close_wav(self): + if self._wav_file: + self._wav_file.close() + self._wav_file = None + if self._wav_io: + self._wav_io.close() + self._wav_io = None + async def start(self, frame: StartFrame): """Start the Tavus video service. @@ -216,6 +241,7 @@ class TavusVideoService(AIService): await self._client.register_audio_destination( self._transport_destination, auto_silence=False ) + self._open_wav(self._client.out_sample_rate) await self._create_send_task() async def stop(self, frame: EndFrame): @@ -227,6 +253,7 @@ class TavusVideoService(AIService): await super().stop(frame) await self._end_conversation() await self._cancel_send_task() + self._close_wav() async def cancel(self, frame: CancelFrame): """Cancel the Tavus video service. @@ -237,6 +264,7 @@ class TavusVideoService(AIService): await super().cancel(frame) await self._end_conversation() await self._cancel_send_task() + self._close_wav() async def process_frame(self, frame: Frame, direction: FrameDirection): """Process frames through the service. @@ -312,5 +340,7 @@ class TavusVideoService(AIService): while True: frame = await self._queue.get() if isinstance(frame, OutputAudioRawFrame) and self._client: + if self._wav_file: + self._wav_file.writeframes(frame.audio) await self._client.write_audio_frame(frame) self._queue.task_done()