From ff0f3dce3209e38867e0eba97323bb328fb327f4 Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Wed, 25 Feb 2026 15:10:11 -0500 Subject: [PATCH] A few Groq-related tweaks: - Wire up passing speed setting to Groq, even though only a value of 1.0 is supported today - Update the 55y example to switch voices instead of changing speed - Add a 55zn example to exercise runtime updates of Groq STT --- .../55y-update-settings-groq-tts.py | 4 +- .../55zzn-update-settings-groq-stt.py | 128 ++++++++++++++++++ src/pipecat/services/groq/tts.py | 3 + 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 examples/foundational/55zzn-update-settings-groq-stt.py diff --git a/examples/foundational/55y-update-settings-groq-tts.py b/examples/foundational/55y-update-settings-groq-tts.py index 86dc1f98a..3531509f2 100644 --- a/examples/foundational/55y-update-settings-groq-tts.py +++ b/examples/foundational/55y-update-settings-groq-tts.py @@ -97,8 +97,8 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): await task.queue_frames([LLMRunFrame()]) await asyncio.sleep(10) - logger.info("Updating Groq TTS settings: speed=1.5") - await task.queue_frame(TTSUpdateSettingsFrame(delta=GroqTTSSettings(speed=1.5))) + logger.info("Updating Groq TTS settings: voice=troy") + await task.queue_frame(TTSUpdateSettingsFrame(delta=GroqTTSSettings(voice="troy"))) @transport.event_handler("on_client_disconnected") async def on_client_disconnected(transport, client): diff --git a/examples/foundational/55zzn-update-settings-groq-stt.py b/examples/foundational/55zzn-update-settings-groq-stt.py new file mode 100644 index 000000000..b00ecda81 --- /dev/null +++ b/examples/foundational/55zzn-update-settings-groq-stt.py @@ -0,0 +1,128 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +import asyncio +import os + +from dotenv import load_dotenv +from loguru import logger + +from pipecat.audio.vad.silero import SileroVADAnalyzer +from pipecat.frames.frames import LLMRunFrame, STTUpdateSettingsFrame +from pipecat.pipeline.pipeline import Pipeline +from pipecat.pipeline.runner import PipelineRunner +from pipecat.pipeline.task import PipelineParams, PipelineTask +from pipecat.processors.aggregators.llm_context import LLMContext +from pipecat.processors.aggregators.llm_response_universal import ( + LLMContextAggregatorPair, + LLMUserAggregatorParams, +) +from pipecat.runner.types import RunnerArguments +from pipecat.runner.utils import create_transport +from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.groq.stt import GroqSTTService +from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.whisper.base_stt import BaseWhisperSTTSettings +from pipecat.transports.base_transport import BaseTransport, TransportParams +from pipecat.transports.daily.transport import DailyParams +from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams + +load_dotenv(override=True) + +transport_params = { + "daily": lambda: DailyParams( + audio_in_enabled=True, + audio_out_enabled=True, + ), + "twilio": lambda: FastAPIWebsocketParams( + audio_in_enabled=True, + audio_out_enabled=True, + ), + "webrtc": lambda: TransportParams( + audio_in_enabled=True, + audio_out_enabled=True, + ), +} + + +async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): + logger.info(f"Starting bot") + + stt = GroqSTTService( + api_key=os.getenv("GROQ_API_KEY"), + ) + + tts = CartesiaTTSService( + api_key=os.getenv("CARTESIA_API_KEY"), + voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ) + + llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) + + messages = [ + { + "role": "system", + "content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Respond to what the user said in a creative and helpful way.", + }, + ] + + context = LLMContext(messages) + user_aggregator, assistant_aggregator = LLMContextAggregatorPair( + context, + user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), + ) + + pipeline = Pipeline( + [ + transport.input(), + stt, + user_aggregator, + llm, + tts, + transport.output(), + assistant_aggregator, + ] + ) + + task = PipelineTask( + pipeline, + params=PipelineParams( + enable_metrics=True, + enable_usage_metrics=True, + ), + idle_timeout_secs=runner_args.pipeline_idle_timeout_secs, + ) + + @transport.event_handler("on_client_connected") + async def on_client_connected(transport, client): + logger.info(f"Client connected") + messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + await task.queue_frames([LLMRunFrame()]) + + await asyncio.sleep(10) + logger.info('Updating Groq STT settings: language="es"') + await task.queue_frame(STTUpdateSettingsFrame(delta=BaseWhisperSTTSettings(language="es"))) + + @transport.event_handler("on_client_disconnected") + async def on_client_disconnected(transport, client): + logger.info(f"Client disconnected") + await task.cancel() + + runner = PipelineRunner(handle_sigint=runner_args.handle_sigint) + + await runner.run(task) + + +async def bot(runner_args: RunnerArguments): + """Main bot entry point compatible with Pipecat Cloud.""" + transport = await create_transport(runner_args, transport_params) + await run_bot(transport, runner_args) + + +if __name__ == "__main__": + from pipecat.runner.run import main + + main() diff --git a/src/pipecat/services/groq/tts.py b/src/pipecat/services/groq/tts.py index cc073f8c7..95ee6faa3 100644 --- a/src/pipecat/services/groq/tts.py +++ b/src/pipecat/services/groq/tts.py @@ -152,6 +152,9 @@ class GroqTTSService(TTSService): model=self._settings.model, voice=self._settings.voice, response_format=self._output_format, + # Note: as of 2026-02-25, only a speed of 1.0 is supported, but + # here we pass it for completeness and future-proofing + speed=self._settings.speed, input=text, )