fixes based on markbackman review

This commit is contained in:
ivaaan
2025-10-01 17:23:55 -07:00
parent 4ffdabcfde
commit c1492c5275
4 changed files with 13 additions and 51 deletions

View File

@@ -7,22 +7,21 @@
import os
from dotenv import load_dotenv
from loguru import logger
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.frames.frames import StartFrame
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair
from pipecat.runner.types import RunnerArguments
from pipecat.runner.utils import create_transport
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.hume.tts import HUME_SAMPLE_RATE, HumeTTSService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import BaseTransport, TransportParams
from pipecat.transports.network.fastapi_websocket import FastAPIWebsocketParams
from pipecat.transports.services.daily import DailyParams
from pipecat.transports.daily.transport import DailyParams
from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams
load_dotenv(override=True)
@@ -40,12 +39,7 @@ transport_params = {
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
"webrtc": lambda: TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
audio_out_sample_rate=HUME_SAMPLE_RATE,
),
"webrtc": lambda: TransportParams(),
}
@@ -69,8 +63,8 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
},
]
context = OpenAILLMContext(messages)
context_aggregator = llm.create_context_aggregator(context)
context = LLMContext(messages)
context_aggregator = LLMContextAggregatorPair(context)
pipeline = Pipeline(
[
@@ -89,6 +83,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
audio_out_sample_rate=HUME_SAMPLE_RATE,
),
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
)
@@ -98,7 +93,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
logger.info(f"Client connected")
# Kick off the conversation.
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
await task.queue_frames([context_aggregator.user().get_context_frame()])
await task.queue_frames([LLMRunFrame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
@@ -112,7 +107,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
async def bot(runner_args: RunnerArguments):
"""Main bot entry point compatible with Pipecat Cloud."""
runner_args.transport = "webrtc"
transport = await create_transport(runner_args, transport_params)
await run_bot(transport, runner_args)

View File

@@ -112,11 +112,6 @@ webrtc = [ "aiortc>=1.13.0,<2", "opencv-python>=4.11.0.86,<5" ]
websocket = [ "pipecat-ai[websockets-base]", "fastapi>=0.115.6,<0.117.0" ]
websockets-base = [ "websockets>=13.1,<16.0" ]
whisper = [ "faster-whisper~=1.1.1" ]
fastapi = [
"fastapi",
"uvicorn",
"websockets",
]
[dependency-groups]
dev = [

View File

@@ -4,8 +4,6 @@
"""Hume Text-to-Speech service implementation."""
from __future__ import annotations
import base64
import os
from typing import Any, AsyncGenerator, Optional
@@ -34,7 +32,7 @@ try:
except ModuleNotFoundError as e: # pragma: no cover - import-time guidance
logger.error(f"Exception: {e}")
logger.error("In order to use Hume, you need to `pip install pipecat-ai[hume]`.")
raise
raise Exception(f"Missing module: {e}")
HUME_SAMPLE_RATE = 48_000 # Hume TTS streams at 48 kHz
@@ -94,11 +92,7 @@ class HumeTTSService(TTSService):
f"Hume TTS streams at {HUME_SAMPLE_RATE} Hz; configured sample_rate={sample_rate}"
)
super().__init__(
pause_frame_processing=True,
sample_rate=sample_rate,
**kwargs,
)
super().__init__(sample_rate=sample_rate, **kwargs)
self._client = AsyncHumeClient(api_key=api_key)
self._params = params or HumeTTSService.InputParams()
@@ -181,7 +175,6 @@ class HumeTTSService(TTSService):
# Request raw PCM chunks in the streaming JSON
pcm_fmt = FormatPcm(type="pcm")
measuring_ttfb = True
await self.start_ttfb_metrics()
await self.start_tts_usage_metrics(text)
yield TTSStartedFrame()
@@ -191,7 +184,6 @@ class HumeTTSService(TTSService):
# Hume emits mono PCM at 48 kHz; downstream can resample if needed.
# We buffer audio bytes before sending to prevent glitches.
self._audio_bytes = b""
first_audio_sent = False
async for chunk in self._client.tts.synthesize_json_streaming(
utterances=[utterance],
format=pcm_fmt,
@@ -204,17 +196,6 @@ class HumeTTSService(TTSService):
pcm_bytes = base64.b64decode(audio_b64)
self._audio_bytes += pcm_bytes
# Send the first audio chunk immediately to avoid client-side delays.
if not first_audio_sent:
if self._audio_bytes:
yield TTSAudioRawFrame(self._audio_bytes, self.sample_rate, 1)
if measuring_ttfb:
await self.stop_ttfb_metrics()
measuring_ttfb = False
first_audio_sent = True
# Do NOT clear _audio_bytes here. Subsequent chunks will build on this.
continue
# Buffer audio until we have enough to avoid glitches
if len(self._audio_bytes) < self.chunk_size:
continue
@@ -226,14 +207,5 @@ class HumeTTSService(TTSService):
logger.exception(f"{self} error generating TTS: {e}")
yield ErrorFrame(error=str(e))
finally:
# Yield any remaining audio
if self._audio_bytes:
yield TTSAudioRawFrame(self._audio_bytes, self.sample_rate, 1)
# Ensure TTFB timer is stopped even on early failures
if measuring_ttfb:
await self.stop_ttfb_metrics()
yield TTSStoppedFrame()
__all__ = ["HumeTTSService"]

View File

@@ -142,6 +142,7 @@ class TTSService(AIService):
"""
return self._sample_rate
@property
def chunk_size(self) -> int:
"""Get the recommended chunk size for audio streaming.