diff --git a/COMMUNITY_INTEGRATIONS.md b/COMMUNITY_INTEGRATIONS.md index ff8d08ea5..5dd9e5764 100644 --- a/COMMUNITY_INTEGRATIONS.md +++ b/COMMUNITY_INTEGRATIONS.md @@ -231,49 +231,102 @@ def can_generate_metrics(self) -> bool: return True ``` -### Dynamic Settings Updates +### Service Settings -STT, LLM, and TTS services support runtime configuration changes via `*UpdateSettingsFrame`s (e.g. `STTUpdateSettingsFrame`, `TTSUpdateSettingsFrame`, `LLMUpdateSettingsFrame`). +Every STT, LLM, TTS, and image-generation service exposes a **Settings dataclass** that serves two roles: -Each service declares a settings dataclass that extends the appropriate base (`STTSettings`, `TTSSettings`, `LLMSettings`). Fields default to `NOT_GIVEN` so that update objects can represent sparse deltas: +1. **Store mode** — the service's `self._settings` holds the current value of every runtime-updatable field. +2. **Delta mode** — an update frame carries only the fields that changed; unset fields remain `NOT_GIVEN`. + +#### Defining your Settings class + +Extend `STTSettings`, `TTSSettings`, `LLMSettings`, or `ImageGenSettings`. The base classes already provide common fields (e.g. `model`, `voice`, `language`). You only need to add **service-specific knobs that should be runtime-updatable**: ```python from dataclasses import dataclass, field -from pipecat.services.settings import STTSettings, NOT_GIVEN +from pipecat.services.settings import TTSSettings, NOT_GIVEN @dataclass -class MySTTSettings(STTSettings): - """Settings for my STT service. +class MyTTSSettings(TTSSettings): + """Settings for MyTTS service. Parameters: - region: Cloud region for the service. + speaking_rate: Speed multiplier (0.5–2.0). """ - region: str = field(default_factory=lambda: NOT_GIVEN) + speaking_rate: float | None = field(default_factory=lambda: NOT_GIVEN) ``` -The service stores its current settings in `self._settings` and declares the type with a class-level annotation for editor support: +**What goes in Settings vs. `__init__` params:** + +| Belongs in Settings | Stays as `__init__` params | +| -------------------------------------------------------- | ----------------------------------------- | +| Model name, voice, language | API keys, auth tokens | +| Service-specific tuning knobs (rate, pitch, temperature) | Base URLs, endpoint overrides | +| Anything users may want to change mid-session | Audio encoding, sample format | +| | Connection parameters (timeouts, retries) | + +The rule of thumb: if a caller might send an update frame to change it at runtime, it belongs in Settings. Everything else is init-only config stored as `self._xxx`. + +#### Wiring settings into `__init__` + +Accept an **optional** `settings` parameter. Build a `default_settings` object with all fields set to real values, then merge any caller overrides with `apply_update`: ```python -class MySTTService(STTService): - _settings: MySTTSettings +from typing import Optional - def __init__(self, *, model: str, language: str, region: str, **kwargs): - # An initial value should be provided for every settings field. - # This will be validated at service start. - # (If you track sample_rate, it can be a placeholder value like 0; see - # "Sample Rate Handling"). - super().__init__( - settings=MySTTSettings(model=model, language=language, region=region), **kwargs +class MyTTSService(TTSService): + _settings: MyTTSSettings + + def __init__( + self, + *, + api_key: str, + settings: Optional[MyTTSSettings] = None, + **kwargs, + ): + # 1. Defaults — every field has a real value (store mode). + default_settings = MyTTSSettings( + model="my-model-v1", + voice="default-voice", + language="en", + speaking_rate=1.0, ) + + # 2. Merge caller overrides (only given fields win). + if settings is not None: + default_settings.apply_update(settings) + + # 3. Pass the fully-populated settings to the base class. + super().__init__(settings=default_settings, **kwargs) + + # 4. Init-only config stored separately. + self._api_key = api_key ``` +This pattern lets callers override only what they care about: + +```python +# Uses all defaults +svc = MyTTSService(api_key="sk-xxx") + +# Overrides just the voice +svc = MyTTSService( + api_key="sk-xxx", + settings=MyTTSSettings(voice="custom-voice"), +) +``` + +#### Reacting to runtime changes + +STT, LLM, and TTS services support runtime configuration changes via `*UpdateSettingsFrame`s (e.g. `STTUpdateSettingsFrame`, `TTSUpdateSettingsFrame`, `LLMUpdateSettingsFrame`). + To react to runtime setting changes, override `_update_settings`. The base implementation applies the delta to `self._settings` and returns a `dict` mapping each changed field name to its **pre-update** value. Your override should call `super()` first, then act on the changed fields. A common implementation might look like: ```python -async def _update_settings(self, update: STTSettings) -> dict[str, Any]: - """Apply a settings update, reconfiguring the recognizer if needed.""" +async def _update_settings(self, update: TTSSettings) -> dict[str, Any]: + """Apply a settings update, reconfiguring the connection if needed.""" changed = await super()._update_settings(update) if not changed: @@ -292,7 +345,7 @@ Note that, in this example, the service requires a reconnect to apply the new la If your service can't yet apply certain settings at runtime, call `self._warn_unhandled_updated_settings(changed)` with any unhandled field names so users get a clear log message: ```python -async def _update_settings(self, update: STTSettings) -> dict[str, Any]: +async def _update_settings(self, update: TTSSettings) -> dict[str, Any]: changed = await super()._update_settings(update) if not changed: diff --git a/examples/foundational/01-say-one-thing-piper.py b/examples/foundational/01-say-one-thing-piper.py index cace8dbeb..6c4e1836e 100644 --- a/examples/foundational/01-say-one-thing-piper.py +++ b/examples/foundational/01-say-one-thing-piper.py @@ -39,7 +39,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Create an HTTP session async with aiohttp.ClientSession() as session: tts = PiperHttpTTSService( - base_url=os.getenv("PIPER_BASE_URL"), aiohttp_session=session, sample_rate=24000 + base_url=os.getenv("PIPER_BASE_URL"), + aiohttp_session=session, + sample_rate=24000, ) task = PipelineTask( diff --git a/examples/foundational/01-say-one-thing-rime.py b/examples/foundational/01-say-one-thing-rime.py index 2a31efa68..63667fac8 100644 --- a/examples/foundational/01-say-one-thing-rime.py +++ b/examples/foundational/01-say-one-thing-rime.py @@ -16,7 +16,7 @@ from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.rime.tts import RimeHttpTTSService +from pipecat.services.rime.tts import RimeHttpTTSService, RimeTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -39,8 +39,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async with aiohttp.ClientSession() as session: tts = RimeHttpTTSService( api_key=os.getenv("RIME_API_KEY", ""), - voice_id="rex", aiohttp_session=session, + settings=RimeTTSSettings( + voice="rex", + ), ) task = PipelineTask( diff --git a/examples/foundational/01-say-one-thing.py b/examples/foundational/01-say-one-thing.py index 7df26701c..bfcf829cc 100644 --- a/examples/foundational/01-say-one-thing.py +++ b/examples/foundational/01-say-one-thing.py @@ -15,7 +15,7 @@ from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -37,7 +37,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) task = PipelineTask( diff --git a/examples/foundational/01a-local-audio.py b/examples/foundational/01a-local-audio.py index 432880203..77565dffe 100644 --- a/examples/foundational/01a-local-audio.py +++ b/examples/foundational/01a-local-audio.py @@ -15,7 +15,7 @@ from pipecat.frames.frames import EndFrame, TTSSpeakFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.transports.local.audio import LocalAudioTransport, LocalAudioTransportParams load_dotenv(override=True) @@ -29,7 +29,9 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) pipeline = Pipeline([tts, transport.output()]) diff --git a/examples/foundational/01b-livekit-audio.py b/examples/foundational/01b-livekit-audio.py index a7697646e..ad4c785eb 100644 --- a/examples/foundational/01b-livekit-audio.py +++ b/examples/foundational/01b-livekit-audio.py @@ -16,7 +16,7 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask from pipecat.runner.livekit import configure -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.transports.livekit.transport import LiveKitParams, LiveKitTransport load_dotenv(override=True) @@ -37,7 +37,9 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) runner = PipelineRunner() diff --git a/examples/foundational/02-llm-say-one-thing.py b/examples/foundational/02-llm-say-one-thing.py index 9cfd7c39e..988ff634f 100644 --- a/examples/foundational/02-llm-say-one-thing.py +++ b/examples/foundational/02-llm-say-one-thing.py @@ -16,8 +16,8 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -39,12 +39,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are an LLM in a WebRTC session, and this is a 'hello world' demo.", + settings=OpenAILLMSettings( + system_instruction="You are an LLM in a WebRTC session, and this is a 'hello world' demo.", + ), ) task = PipelineTask( diff --git a/examples/foundational/03-still-frame.py b/examples/foundational/03-still-frame.py index def125165..a98a53637 100644 --- a/examples/foundational/03-still-frame.py +++ b/examples/foundational/03-still-frame.py @@ -16,7 +16,7 @@ from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.fal.image import FalImageGenService +from pipecat.services.fal.image import FalImageGenService, FalImageGenSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -45,7 +45,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Create an HTTP session async with aiohttp.ClientSession() as session: imagegen = FalImageGenService( - params=FalImageGenService.InputParams(image_size="square_hd"), + settings=FalImageGenSettings( + image_size="square_hd", + ), aiohttp_session=session, key=os.getenv("FAL_KEY"), ) diff --git a/examples/foundational/03a-local-still-frame.py b/examples/foundational/03a-local-still-frame.py index b25c51c4a..db67848e8 100644 --- a/examples/foundational/03a-local-still-frame.py +++ b/examples/foundational/03a-local-still-frame.py @@ -17,7 +17,7 @@ from pipecat.frames.frames import TextFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineTask -from pipecat.services.fal.image import FalImageGenService +from pipecat.services.fal.image import FalImageGenService, FalImageGenSettings from pipecat.transports.local.tk import TkLocalTransport, TkTransportParams load_dotenv(override=True) @@ -37,7 +37,9 @@ async def main(): ) imagegen = FalImageGenService( - params=FalImageGenService.InputParams(image_size="square_hd"), + settings=FalImageGenSettings( + image_size="square_hd", + ), aiohttp_session=session, key=os.getenv("FAL_KEY"), ) diff --git a/examples/foundational/04-transports-small-webrtc.py b/examples/foundational/04-transports-small-webrtc.py index d29171dd2..a26fdf5c0 100644 --- a/examples/foundational/04-transports-small-webrtc.py +++ b/examples/foundational/04-transports-small-webrtc.py @@ -27,9 +27,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import TransportParams from pipecat.transports.smallwebrtc.connection import IceServer, SmallWebRTCConnection from pipecat.transports.smallwebrtc.transport import SmallWebRTCTransport @@ -67,12 +67,16 @@ async def run_example(webrtc_connection: SmallWebRTCConnection): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/04a-transports-daily.py b/examples/foundational/04a-transports-daily.py index b0a7958ef..15b5e20e2 100644 --- a/examples/foundational/04a-transports-daily.py +++ b/examples/foundational/04a-transports-daily.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMUserAggregatorParams, ) from pipecat.runner.daily import configure -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.daily.transport import DailyParams, DailyTransport load_dotenv(override=True) @@ -50,13 +50,17 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o", - system_instruction="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.", + settings=OpenAILLMSettings( + model="gpt-4o", + system_instruction="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() diff --git a/examples/foundational/04b-transports-livekit.py b/examples/foundational/04b-transports-livekit.py index e05c5ddc3..1f4709b0b 100644 --- a/examples/foundational/04b-transports-livekit.py +++ b/examples/foundational/04b-transports-livekit.py @@ -29,9 +29,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMUserAggregatorParams, ) from pipecat.runner.livekit import configure -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.livekit.transport import LiveKitParams, LiveKitTransport load_dotenv(override=True) @@ -57,12 +57,16 @@ async def main(): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) context = LLMContext() diff --git a/examples/foundational/05-sync-speech-and-image.py b/examples/foundational/05-sync-speech-and-image.py index c1b142670..b77ff1612 100644 --- a/examples/foundational/05-sync-speech-and-image.py +++ b/examples/foundational/05-sync-speech-and-image.py @@ -27,8 +27,8 @@ from pipecat.processors.aggregators.sentence import SentenceAggregator from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaHttpTTSService -from pipecat.services.fal.image import FalImageGenService +from pipecat.services.cartesia.tts import CartesiaHttpTTSService, CartesiaTTSSettings +from pipecat.services.fal.image import FalImageGenService, FalImageGenSettings from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -98,11 +98,15 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaHttpTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) imagegen = FalImageGenService( - params=FalImageGenService.InputParams(image_size="square_hd"), + settings=FalImageGenSettings( + image_size="square_hd", + ), aiohttp_session=session, key=os.getenv("FAL_KEY"), ) diff --git a/examples/foundational/05a-local-sync-speech-and-image.py b/examples/foundational/05a-local-sync-speech-and-image.py index 56309c0a5..993e8eb07 100644 --- a/examples/foundational/05a-local-sync-speech-and-image.py +++ b/examples/foundational/05a-local-sync-speech-and-image.py @@ -28,8 +28,8 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.sentence import SentenceAggregator from pipecat.processors.frame_processor import FrameDirection, FrameProcessor -from pipecat.services.cartesia.tts import CartesiaHttpTTSService -from pipecat.services.fal.image import FalImageGenService +from pipecat.services.cartesia.tts import CartesiaHttpTTSService, CartesiaTTSSettings +from pipecat.services.fal.image import FalImageGenService, FalImageGenSettings from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.local.tk import TkLocalTransport, TkTransportParams @@ -98,11 +98,15 @@ async def main(): tts = CartesiaHttpTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) imagegen = FalImageGenService( - params=FalImageGenService.InputParams(image_size="square_hd"), + settings=FalImageGenSettings( + image_size="square_hd", + ), aiohttp_session=session, key=os.getenv("FAL_KEY"), ) diff --git a/examples/foundational/06-listen-and-respond.py b/examples/foundational/06-listen-and-respond.py index 418b3b5af..1e2f88a93 100644 --- a/examples/foundational/06-listen-and-respond.py +++ b/examples/foundational/06-listen-and-respond.py @@ -28,9 +28,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -83,12 +83,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) ml = MetricsLogger() diff --git a/examples/foundational/06a-image-sync.py b/examples/foundational/06a-image-sync.py index f963aa339..007a41143 100644 --- a/examples/foundational/06a-image-sync.py +++ b/examples/foundational/06a-image-sync.py @@ -29,9 +29,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -100,12 +100,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07-interruptible-cartesia-http.py b/examples/foundational/07-interruptible-cartesia-http.py index 8ce1ed375..ac409f55d 100644 --- a/examples/foundational/07-interruptible-cartesia-http.py +++ b/examples/foundational/07-interruptible-cartesia-http.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.stt import CartesiaSTTService -from pipecat.services.cartesia.tts import CartesiaHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaHttpTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -58,13 +58,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaHttpTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady aiohttp_session=session, + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07-interruptible.py b/examples/foundational/07-interruptible.py index 3f97e5028..05a751a68 100644 --- a/examples/foundational/07-interruptible.py +++ b/examples/foundational/07-interruptible.py @@ -21,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.tts_service import TextAggregationMode from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,15 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady - # Alternatively, you can use TextAggregationMode.TOKEN to stream tokens instead of - # sentencesfor faster response times. - # text_aggregation_mode=TextAggregationMode.TOKEN, + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07a-interruptible-speechmatics-vad.py b/examples/foundational/07a-interruptible-speechmatics-vad.py index d75ae2b1f..a6a287f83 100644 --- a/examples/foundational/07a-interruptible-speechmatics-vad.py +++ b/examples/foundational/07a-interruptible-speechmatics-vad.py @@ -21,10 +21,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.base_llm import BaseOpenAILLMService +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.speechmatics.stt import SpeechmaticsSTTService -from pipecat.services.speechmatics.tts import SpeechmaticsTTSService +from pipecat.services.speechmatics.stt import SpeechmaticsSTTService, SpeechmaticsSTTSettings +from pipecat.services.speechmatics.tts import SpeechmaticsTTSService, SpeechmaticsTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -93,7 +93,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async with aiohttp.ClientSession() as session: stt = SpeechmaticsSTTService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - params=SpeechmaticsSTTService.InputParams( + settings=SpeechmaticsSTTSettings( language=Language.EN, turn_detection_mode=SpeechmaticsSTTService.TurnDetectionMode.ADAPTIVE, # focus_speakers=["S1"], @@ -104,32 +104,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = SpeechmaticsTTSService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - voice_id="sarah", + settings=SpeechmaticsTTSSettings( + voice="sarah", + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - params=BaseOpenAILLMService.InputParams(temperature=0.75), + settings=OpenAILLMSettings( + temperature=0.75, + system_instruction="You are a helpful British assistant called Sarah. 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. Always include punctuation in your responses. Give very short replies - do not give longer replies unless strictly necessary. Respond to what the user said in a concise, funny, creative and helpful way. Use `` tags to identify different speakers - do not use tags in your replies. Do not respond to speakers within `` tags unless explicitly asked to.", + ), ) - messages = [ - { - "role": "system", - "content": ( - "You are a helpful British assistant called Sarah. " - "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. " - "Always include punctuation in your responses. " - "Give very short replies - do not give longer replies unless strictly necessary. " - "Respond to what the user said in a concise, funny, creative and helpful way. " - "Use `` tags to identify different speakers - do not use tags in your replies. " - "Do not respond to speakers within `` tags unless explicitly asked to. " - ), - }, - ] - - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(user_turn_strategies=ExternalUserTurnStrategies()), @@ -160,7 +149,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Say a short hello to the user."}) + context.add_message({"role": "system", "content": "Say a short hello to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/07a-interruptible-speechmatics.py b/examples/foundational/07a-interruptible-speechmatics.py index f8b4cdf19..d4e4dc638 100644 --- a/examples/foundational/07a-interruptible-speechmatics.py +++ b/examples/foundational/07a-interruptible-speechmatics.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.base_llm import BaseOpenAILLMService +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.speechmatics.stt import SpeechmaticsSTTService -from pipecat.services.speechmatics.tts import SpeechmaticsTTSService +from pipecat.services.speechmatics.stt import SpeechmaticsSTTService, SpeechmaticsSTTSettings +from pipecat.services.speechmatics.tts import SpeechmaticsTTSService, SpeechmaticsTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -76,7 +76,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async with aiohttp.ClientSession() as session: stt = SpeechmaticsSTTService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - params=SpeechmaticsSTTService.InputParams( + settings=SpeechmaticsSTTSettings( language=Language.EN, speaker_active_format="<{speaker_id}>{text}", ), @@ -84,31 +84,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = SpeechmaticsTTSService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - voice_id="sarah", + settings=SpeechmaticsTTSSettings( + voice="sarah", + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - params=BaseOpenAILLMService.InputParams(temperature=0.75), + settings=OpenAILLMSettings( + temperature=0.75, + system_instruction="You are a helpful British assistant called Sarah. 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. Always include punctuation in your responses. Give very short replies - do not give longer replies unless strictly necessary. Respond to what the user said in a concise, funny, creative and helpful way. Use `` tags to identify different speakers - do not use tags in your replies. Do not respond to speakers within `` tags unless explicitly asked to.", + ), ) - messages = [ - { - "role": "system", - "content": ( - "You are a helpful British assistant called Sarah. " - "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. " - "Always include punctuation in your responses. " - "Give very short replies - do not give longer replies unless strictly necessary. " - "Respond to what the user said in a concise, funny, creative and helpful way. " - "Use `` tags to identify different speakers - do not use tags in your replies." - ), - }, - ] - - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -139,7 +129,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Say a short hello to the user."}) + context.add_message({"role": "system", "content": "Say a short hello to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/07b-interruptible-langchain.py b/examples/foundational/07b-interruptible-langchain.py index 21290b576..e7a5dc1b8 100644 --- a/examples/foundational/07b-interruptible-langchain.py +++ b/examples/foundational/07b-interruptible-langchain.py @@ -28,7 +28,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frameworks.langchain import LangchainProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -71,7 +71,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) prompt = ChatPromptTemplate.from_messages( diff --git a/examples/foundational/07c-interruptible-deepgram-flux.py b/examples/foundational/07c-interruptible-deepgram-flux.py index 3f2d6e28d..c205c5141 100644 --- a/examples/foundational/07c-interruptible-deepgram-flux.py +++ b/examples/foundational/07c-interruptible-deepgram-flux.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.deepgram.flux.stt import DeepgramFluxSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.flux.stt import DeepgramFluxSTTService, DeepgramFluxSTTSettings +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,14 +56,23 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramFluxSTTService( api_key=os.getenv("DEEPGRAM_API_KEY"), - params=DeepgramFluxSTTService.InputParams(min_confidence=0.3), + settings=DeepgramFluxSTTSettings( + min_confidence=0.3, + ), ) - tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-2-andromeda-en") + tts = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-2-andromeda-en", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07c-interruptible-deepgram-http.py b/examples/foundational/07c-interruptible-deepgram-http.py index 6955ccbd1..b4d829e96 100644 --- a/examples/foundational/07c-interruptible-deepgram-http.py +++ b/examples/foundational/07c-interruptible-deepgram-http.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.tts import DeepgramHttpTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,18 +59,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = DeepgramHttpTTSService( api_key=os.getenv("DEEPGRAM_API_KEY"), - voice="aura-2-andromeda-en", + settings=DeepgramTTSSettings( + voice="aura-2-andromeda-en", + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) - messages = [] - - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/07c-interruptible-deepgram-sagemaker.py b/examples/foundational/07c-interruptible-deepgram-sagemaker.py index 406f95445..b1c54a27e 100644 --- a/examples/foundational/07c-interruptible-deepgram-sagemaker.py +++ b/examples/foundational/07c-interruptible-deepgram-sagemaker.py @@ -22,9 +22,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.aws.llm import AWSBedrockLLMService +from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings from pipecat.services.deepgram.sagemaker.stt import DeepgramSageMakerSTTService -from pipecat.services.deepgram.sagemaker.tts import DeepgramSageMakerTTSService +from pipecat.services.deepgram.sagemaker.tts import ( + DeepgramSageMakerTTSService, + DeepgramSageMakerTTSSettings, +) from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -69,14 +72,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = DeepgramSageMakerTTSService( endpoint_name=os.getenv("SAGEMAKER_TTS_ENDPOINT_NAME"), region=os.getenv("AWS_REGION"), - voice="aura-2-andromeda-en", + settings=DeepgramSageMakerTTSSettings( + voice="aura-2-andromeda-en", + ), ) llm = AWSBedrockLLMService( aws_region=os.getenv("AWS_REGION"), - model="us.amazon.nova-pro-v1:0", - params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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.", + settings=AWSBedrockLLMSettings( + model="us.amazon.nova-pro-v1:0", + temperature=0.8, + system_instruction="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() diff --git a/examples/foundational/07c-interruptible-deepgram-vad.py b/examples/foundational/07c-interruptible-deepgram-vad.py index aaa81fc90..4af1b0c72 100644 --- a/examples/foundational/07c-interruptible-deepgram-vad.py +++ b/examples/foundational/07c-interruptible-deepgram-vad.py @@ -7,7 +7,6 @@ import os -from deepgram import LiveOptions from dotenv import load_dotenv from loguru import logger @@ -22,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.stt import DeepgramSTTService, DeepgramSTTSettings +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,14 +55,24 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService( api_key=os.getenv("DEEPGRAM_API_KEY"), - live_options=LiveOptions(vad_events=True, utterance_end_ms="1000"), + settings=DeepgramSTTSettings( + vad_events=True, + utterance_end_ms="1000", + ), ) - tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-2-andromeda-en") + tts = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-2-andromeda-en", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07c-interruptible-deepgram.py b/examples/foundational/07c-interruptible-deepgram.py index 1cbfc72cc..1a10c0b28 100644 --- a/examples/foundational/07c-interruptible-deepgram.py +++ b/examples/foundational/07c-interruptible-deepgram.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,11 +55,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-2-andromeda-en") + tts = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-2-andromeda-en", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07d-interruptible-elevenlabs-http.py b/examples/foundational/07d-interruptible-elevenlabs-http.py index 85cffc270..a7f68a599 100644 --- a/examples/foundational/07d-interruptible-elevenlabs-http.py +++ b/examples/foundational/07d-interruptible-elevenlabs-http.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.elevenlabs.stt import ElevenLabsSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.elevenlabs.tts import ElevenLabsHttpTTSService, ElevenLabsHttpTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -63,13 +63,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsHttpTTSService( api_key=os.getenv("ELEVENLABS_API_KEY", ""), - voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), aiohttp_session=session, + settings=ElevenLabsHttpTTSSettings( + voice=os.getenv("ELEVENLABS_VOICE_ID", ""), + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07d-interruptible-elevenlabs.py b/examples/foundational/07d-interruptible-elevenlabs.py index b55345f33..ec62eac4d 100644 --- a/examples/foundational/07d-interruptible-elevenlabs.py +++ b/examples/foundational/07d-interruptible-elevenlabs.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.elevenlabs.stt import ElevenLabsRealtimeSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY", ""), - voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), + settings=ElevenLabsTTSSettings( + voice=os.getenv("ELEVENLABS_VOICE_ID", ""), + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07f-interruptible-azure-http.py b/examples/foundational/07f-interruptible-azure-http.py index 1946f66ee..38b840d6a 100644 --- a/examples/foundational/07f-interruptible-azure-http.py +++ b/examples/foundational/07f-interruptible-azure-http.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.azure.llm import AzureLLMService +from pipecat.services.azure.llm import AzureLLMService, AzureLLMSettings from pipecat.services.azure.stt import AzureSTTService from pipecat.services.azure.tts import AzureHttpTTSService from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -66,7 +66,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): api_key=os.getenv("AZURE_CHATGPT_API_KEY"), endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), model=os.getenv("AZURE_CHATGPT_MODEL"), - system_instruction="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.", + settings=AzureLLMSettings( + system_instruction="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() diff --git a/examples/foundational/07f-interruptible-azure.py b/examples/foundational/07f-interruptible-azure.py index 68f5a72f9..7dafd8e1e 100644 --- a/examples/foundational/07f-interruptible-azure.py +++ b/examples/foundational/07f-interruptible-azure.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.azure.llm import AzureLLMService +from pipecat.services.azure.llm import AzureLLMService, AzureLLMSettings from pipecat.services.azure.stt import AzureSTTService from pipecat.services.azure.tts import AzureTTSService from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -66,7 +66,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): api_key=os.getenv("AZURE_CHATGPT_API_KEY"), endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), model=os.getenv("AZURE_CHATGPT_MODEL"), - system_instruction="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.", + settings=AzureLLMSettings( + system_instruction="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() diff --git a/examples/foundational/07g-interruptible-openai-http.py b/examples/foundational/07g-interruptible-openai-http.py index 05c98ca59..2b841be6a 100644 --- a/examples/foundational/07g-interruptible-openai-http.py +++ b/examples/foundational/07g-interruptible-openai-http.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.openai.stt import OpenAISTTService -from pipecat.services.openai.tts import OpenAITTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.openai.stt import OpenAISTTService, OpenAISTTSettings +from pipecat.services.openai.tts import OpenAITTSService, OpenAITTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,15 +54,24 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = OpenAISTTService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-transcribe", - prompt="Expect words related to dogs, such as breed names.", + settings=OpenAISTTSettings( + model="gpt-4o-transcribe", + prompt="Expect words related to dogs, such as breed names.", + ), ) - tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="ballad") + tts = OpenAITTSService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAITTSSettings( + voice="ballad", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are very knowledgable about dogs. 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.", + settings=OpenAILLMSettings( + system_instruction="You are very knowledgable about dogs. 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() diff --git a/examples/foundational/07g-interruptible-openai.py b/examples/foundational/07g-interruptible-openai.py index a29e8210f..776feeb17 100644 --- a/examples/foundational/07g-interruptible-openai.py +++ b/examples/foundational/07g-interruptible-openai.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.openai.stt import OpenAIRealtimeSTTService -from pipecat.services.openai.tts import OpenAITTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.openai.stt import OpenAIRealtimeSTTService, OpenAIRealtimeSTTSettings +from pipecat.services.openai.tts import OpenAITTSService, OpenAITTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,20 +55,25 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = OpenAIRealtimeSTTService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-transcribe", - prompt="Expect words related to dogs, such as breed names.", - language=Language.EN, - # Uses local VAD by default. - # To enable server-side VAD, set turn_detection=None or - # a dict with server_vad settings. - # turn_detection={"type": "server_vad", "threshold": 0.5}, + settings=OpenAIRealtimeSTTSettings( + model="gpt-4o-transcribe", + prompt="Expect words related to dogs, such as breed names.", + language=Language.EN, + ), ) - tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="ballad") + tts = OpenAITTSService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAITTSSettings( + voice="ballad", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are very knowledgable about dogs. 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.", + settings=OpenAILLMSettings( + system_instruction="You are very knowledgable about dogs. 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() diff --git a/examples/foundational/07h-interruptible-openpipe.py b/examples/foundational/07h-interruptible-openpipe.py index e3ddc05b8..f7cd4d7d9 100644 --- a/examples/foundational/07h-interruptible-openpipe.py +++ b/examples/foundational/07h-interruptible-openpipe.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openpipe.llm import OpenPipeLLMService +from pipecat.services.openpipe.llm import OpenPipeLLMService, OpenPipeLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -57,7 +57,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) timestamp = int(time.time()) @@ -65,7 +67,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): api_key=os.getenv("OPENAI_API_KEY"), openpipe_api_key=os.getenv("OPENPIPE_API_KEY"), tags={"conversation_id": f"pipecat-{timestamp}"}, - system_instruction="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.", + settings=OpenPipeLLMSettings( + system_instruction="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() diff --git a/examples/foundational/07i-interruptible-xtts.py b/examples/foundational/07i-interruptible-xtts.py index 00883e37f..76f139cbf 100644 --- a/examples/foundational/07i-interruptible-xtts.py +++ b/examples/foundational/07i-interruptible-xtts.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.xtts.tts import XTTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.xtts.tts import XTTSService, XTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,13 +59,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = XTTSService( aiohttp_session=session, - voice_id="Claribel Dervla", + settings=XTTSSettings( + voice="Claribel Dervla", + ), base_url="http://localhost:8000", ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07j-interruptible-gladia-vad.py b/examples/foundational/07j-interruptible-gladia-vad.py index f0874f0f3..3bc0c0404 100644 --- a/examples/foundational/07j-interruptible-gladia-vad.py +++ b/examples/foundational/07j-interruptible-gladia-vad.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.gladia.config import GladiaInputParams, LanguageConfig -from pipecat.services.gladia.stt import GladiaSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.gladia.config import LanguageConfig +from pipecat.services.gladia.stt import GladiaSTTService, GladiaSTTSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -58,7 +58,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GladiaSTTService( api_key=os.getenv("GLADIA_API_KEY", ""), region=os.getenv("GLADIA_REGION"), - params=GladiaInputParams( + settings=GladiaSTTSettings( language_config=LanguageConfig( languages=[Language.EN], ), @@ -68,19 +68,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY", ""), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY", "")) + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY", ""), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) - messages = [ - { - "role": "system", - "content": f"You are a helpful LLM. 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) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams( @@ -114,7 +114,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "system", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/07j-interruptible-gladia.py b/examples/foundational/07j-interruptible-gladia.py index 4bebffce7..781e20942 100644 --- a/examples/foundational/07j-interruptible-gladia.py +++ b/examples/foundational/07j-interruptible-gladia.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.gladia.config import GladiaInputParams, LanguageConfig -from pipecat.services.gladia.stt import GladiaSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.gladia.config import LanguageConfig +from pipecat.services.gladia.stt import GladiaSTTService, GladiaSTTSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -57,7 +57,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GladiaSTTService( api_key=os.getenv("GLADIA_API_KEY", ""), region=os.getenv("GLADIA_REGION"), - params=GladiaInputParams( + settings=GladiaSTTSettings( language_config=LanguageConfig( languages=[Language.EN], ) @@ -66,19 +66,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY", ""), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY", "")) + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY", ""), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) - messages = [ - { - "role": "system", - "content": f"You are a helpful LLM. 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) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -109,7 +109,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "system", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/07k-interruptible-lmnt.py b/examples/foundational/07k-interruptible-lmnt.py index 246caee19..cab1bca81 100644 --- a/examples/foundational/07k-interruptible-lmnt.py +++ b/examples/foundational/07k-interruptible-lmnt.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.lmnt.tts import LmntTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.lmnt.tts import LmntTTSService, LmntTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,11 +54,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = LmntTTSService(api_key=os.getenv("LMNT_API_KEY"), voice_id="morgan") + tts = LmntTTSService( + api_key=os.getenv("LMNT_API_KEY"), + settings=LmntTTSSettings( + voice="morgan", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07l-interruptible-groq.py b/examples/foundational/07l-interruptible-groq.py index 5a16d789e..3fe64a460 100644 --- a/examples/foundational/07l-interruptible-groq.py +++ b/examples/foundational/07l-interruptible-groq.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.groq.llm import GroqLLMService +from pipecat.services.groq.llm import GroqLLMService, GroqLLMSettings from pipecat.services.groq.stt import GroqSTTService from pipecat.services.groq.tts import GroqTTSService from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -56,8 +56,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = GroqLLMService( api_key=os.getenv("GROQ_API_KEY"), - model="meta-llama/llama-4-maverick-17b-128e-instruct", - system_instruction="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.", + settings=GroqLLMSettings( + model="meta-llama/llama-4-maverick-17b-128e-instruct", + system_instruction="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.", + ), ) tts = GroqTTSService(api_key=os.getenv("GROQ_API_KEY")) diff --git a/examples/foundational/07m-interruptible-aws-strands.py b/examples/foundational/07m-interruptible-aws-strands.py index 2e0fc18d8..c65709a7b 100644 --- a/examples/foundational/07m-interruptible-aws-strands.py +++ b/examples/foundational/07m-interruptible-aws-strands.py @@ -22,7 +22,7 @@ from pipecat.processors.frameworks.strands_agents import StrandsAgentsProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.aws.stt import AWSTranscribeSTTService -from pipecat.services.aws.tts import AWSPollyTTSService +from pipecat.services.aws.tts import AWSPollyTTSService, AWSPollyTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -95,8 +95,11 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AWSPollyTTSService( region="us-west-2", # only specific regions support generative TTS - voice_id="Joanna", - params=AWSPollyTTSService.InputParams(engine="generative", rate="1.1"), + settings=AWSPollyTTSSettings( + voice="Joanna", + engine="generative", + rate="1.1", + ), ) # Create Strands agent processor diff --git a/examples/foundational/07m-interruptible-aws.py b/examples/foundational/07m-interruptible-aws.py index b30220bcd..8b7c0c29e 100644 --- a/examples/foundational/07m-interruptible-aws.py +++ b/examples/foundational/07m-interruptible-aws.py @@ -20,9 +20,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.aws.llm import AWSBedrockLLMService +from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings from pipecat.services.aws.stt import AWSTranscribeSTTService -from pipecat.services.aws.tts import AWSPollyTTSService +from pipecat.services.aws.tts import AWSPollyTTSService, AWSPollyTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,15 +54,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AWSPollyTTSService( region="us-west-2", # only specific regions support generative TTS - voice_id="Joanna", - params=AWSPollyTTSService.InputParams(engine="generative", rate="1.1"), + settings=AWSPollyTTSSettings( + voice="Joanna", + engine="generative", + rate="1.1", + ), ) llm = AWSBedrockLLMService( aws_region="us-west-2", model="us.anthropic.claude-haiku-4-5-20251001-v1:0", params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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.", + settings=AWSBedrockLLMSettings( + system_instruction="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() diff --git a/examples/foundational/07n-interruptible-gemini-image.py b/examples/foundational/07n-interruptible-gemini-image.py index b7d3281b9..072998fa9 100644 --- a/examples/foundational/07n-interruptible-gemini-image.py +++ b/examples/foundational/07n-interruptible-gemini-image.py @@ -37,9 +37,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.google.llm import GoogleLLMService -from pipecat.services.google.stt import GoogleSTTService -from pipecat.services.google.tts import GoogleTTSService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.google.stt import GoogleSTTService, GoogleSTTSettings +from pipecat.services.google.tts import GoogleTTSService, GoogleTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -70,21 +70,27 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") stt = GoogleSTTService( - params=GoogleSTTService.InputParams(languages=Language.EN_US), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), + settings=GoogleSTTSettings( + languages=Language.EN_US, + ), ) tts = GoogleTTSService( - voice_id="en-US-Chirp3-HD-Charon", - params=GoogleTTSService.InputParams(language=Language.EN_US), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), + settings=GoogleTTSSettings( + voice="en-US-Chirp3-HD-Charon", + language=Language.EN_US, + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - model="gemini-2.5-flash-image", - # model="gemini-3-pro-image-preview", # A more powerful model, but slower, - system_instruction="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.", + settings=GoogleLLMSettings( + model="gemini-2.5-flash-image", + # model="gemini-3-pro-image-preview", # A more powerful model, but slower, + system_instruction="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() diff --git a/examples/foundational/07n-interruptible-gemini.py b/examples/foundational/07n-interruptible-gemini.py index 74f732926..a48efefad 100644 --- a/examples/foundational/07n-interruptible-gemini.py +++ b/examples/foundational/07n-interruptible-gemini.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.google.llm import GoogleLLMService -from pipecat.services.google.stt import GoogleSTTService -from pipecat.services.google.tts import GeminiTTSService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.google.stt import GoogleSTTService, GoogleSTTSettings +from pipecat.services.google.tts import GeminiTTSService, GeminiTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,15 +54,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot with Gemini TTS") stt = GoogleSTTService( - params=GoogleSTTService.InputParams(languages=Language.EN_US), + settings=GoogleSTTSettings( + languages=Language.EN_US, + ), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), ) tts = GeminiTTSService( credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), - model="gemini-2.5-flash-tts", - voice_id="Charon", - params=GeminiTTSService.InputParams( + settings=GeminiTTSSettings( + model="gemini-2.5-flash-tts", + voice="Charon", language=Language.EN_US, prompt="You are a helpful AI assistant. Speak in a natural, conversational tone.", ), @@ -71,7 +73,8 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.5-flash", - system_instruction="""You are a helpful AI assistant in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. + settings=GoogleLLMSettings( + system_instruction="""You are a helpful AI assistant in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. IMPORTANT: You're using Gemini TTS which supports expressive markup tags. You can use these tags in your responses: - [sigh] - Insert a sigh sound @@ -89,6 +92,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): - "The answer is... [long pause] ...42!" 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() diff --git a/examples/foundational/07n-interruptible-google-http.py b/examples/foundational/07n-interruptible-google-http.py index e5f82ffc5..0a6280618 100644 --- a/examples/foundational/07n-interruptible-google-http.py +++ b/examples/foundational/07n-interruptible-google-http.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.google.llm import GoogleLLMService -from pipecat.services.google.stt import GoogleSTTService -from pipecat.services.google.tts import GoogleHttpTTSService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.google.stt import GoogleSTTService, GoogleSTTSettings +from pipecat.services.google.tts import GoogleHttpTTSService, GoogleHttpTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,25 +54,30 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") stt = GoogleSTTService( - params=GoogleSTTService.InputParams(languages=Language.EN_US, model="chirp_3"), + settings=GoogleSTTSettings( + languages=Language.EN_US, + model="chirp_3", + ), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), location="us", ) tts = GoogleHttpTTSService( - voice_id="en-US-Chirp3-HD-Charon", - params=GoogleHttpTTSService.InputParams(language=Language.EN_US), + settings=GoogleHttpTTSSettings( + voice="en-US-Chirp3-HD-Charon", + language=Language.EN_US, + ), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - model="gemini-2.5-flash", - # force a certain amount of thinking if you want it - # params=GoogleLLMService.InputParams( - # thinking=GoogleLLMService.ThinkingConfig(thinking_budget=4096) - # ), - system_instruction="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.", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + # force a certain amount of thinking if you want it + # thinking=GoogleLLMService.ThinkingConfig(thinking_budget=4096) + system_instruction="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() diff --git a/examples/foundational/07n-interruptible-google.py b/examples/foundational/07n-interruptible-google.py index 090fdbbdc..d6c57b548 100644 --- a/examples/foundational/07n-interruptible-google.py +++ b/examples/foundational/07n-interruptible-google.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.google.llm import GoogleLLMService -from pipecat.services.google.stt import GoogleSTTService -from pipecat.services.google.tts import GoogleTTSService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.google.stt import GoogleSTTService, GoogleSTTSettings +from pipecat.services.google.tts import GoogleTTSService, GoogleTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,25 +54,30 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") stt = GoogleSTTService( - params=GoogleSTTService.InputParams(languages=Language.EN_US, model="chirp_3"), + settings=GoogleSTTSettings( + languages=Language.EN_US, + model="chirp_3", + ), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), location="us", ) tts = GoogleTTSService( - voice_id="en-US-Chirp3-HD-Charon", - params=GoogleTTSService.InputParams(language=Language.EN_US), + settings=GoogleTTSSettings( + voice="en-US-Chirp3-HD-Charon", + language=Language.EN_US, + ), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - model="gemini-2.5-flash", - # force a certain amount of thinking if you want it - # params=GoogleLLMService.InputParams( - # thinking=GoogleLLMService.ThinkingConfig(thinking_budget=4096) - # ), - system_instruction="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.", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + # force a certain amount of thinking if you want it + # thinking=GoogleLLMService.ThinkingConfig(thinking_budget=4096), + system_instruction="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() diff --git a/examples/foundational/07o-interruptible-assemblyai-turn-detection.py b/examples/foundational/07o-interruptible-assemblyai-turn-detection.py index 7a0226277..b15e3038f 100644 --- a/examples/foundational/07o-interruptible-assemblyai-turn-detection.py +++ b/examples/foundational/07o-interruptible-assemblyai-turn-detection.py @@ -22,10 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.assemblyai.models import AssemblyAIConnectionParams -from pipecat.services.assemblyai.stt import AssemblyAISTTService -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.assemblyai.stt import AssemblyAISTTService, AssemblyAISTTSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -94,7 +93,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = AssemblyAISTTService( api_key=os.getenv("ASSEMBLYAI_API_KEY"), vad_force_turn_endpoint=False, # Use AssemblyAI's built-in turn detection - connection_params=AssemblyAIConnectionParams( + settings=AssemblyAISTTSettings( speech_model="u3-rt-pro", # Optional: Tune turn detection timing (defaults shown below) # min_turn_silence=100, # Default @@ -108,12 +107,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07o-interruptible-assemblyai.py b/examples/foundational/07o-interruptible-assemblyai.py index 8378f7bba..8e58ddbf3 100644 --- a/examples/foundational/07o-interruptible-assemblyai.py +++ b/examples/foundational/07o-interruptible-assemblyai.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.assemblyai.stt import AssemblyAISTTService -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,12 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07p-interruptible-krisp-viva.py b/examples/foundational/07p-interruptible-krisp-viva.py index 4df652ae0..056a2f6cc 100644 --- a/examples/foundational/07p-interruptible-krisp-viva.py +++ b/examples/foundational/07p-interruptible-krisp-viva.py @@ -43,9 +43,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -84,12 +84,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts = CartesiaTTSService( - api_key=os.getenv("CARTESIA_API_KEY"), voice_id="71a7ad14-091c-4e8e-a314-022ece01c121" + api_key=os.getenv("CARTESIA_API_KEY"), + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07p-interruptible-krisp.py b/examples/foundational/07p-interruptible-krisp.py index ad737ba05..b3ccfb30e 100644 --- a/examples/foundational/07p-interruptible-krisp.py +++ b/examples/foundational/07p-interruptible-krisp.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -58,11 +58,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") + tts = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-helios-en", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07q-interruptible-rime-http.py b/examples/foundational/07q-interruptible-rime-http.py index 4e390b123..ebbdc6946 100644 --- a/examples/foundational/07q-interruptible-rime-http.py +++ b/examples/foundational/07q-interruptible-rime-http.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.rime.tts import RimeHttpTTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.rime.tts import RimeHttpTTSService, RimeTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -60,14 +60,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = RimeHttpTTSService( api_key=os.getenv("RIME_API_KEY", ""), - voice_id="luna", + settings=RimeTTSSettings( + voice="luna", + model="arcana", + ), model="arcana", aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07q-interruptible-rime.py b/examples/foundational/07q-interruptible-rime.py index cebf6bfd0..bfcf5da41 100644 --- a/examples/foundational/07q-interruptible-rime.py +++ b/examples/foundational/07q-interruptible-rime.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.rime.tts import RimeTTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.rime.tts import RimeTTSService, RimeTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = RimeTTSService( api_key=os.getenv("RIME_API_KEY", ""), - voice_id="luna", + settings=RimeTTSSettings( + voice="luna", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07r-interruptible-nvidia.py b/examples/foundational/07r-interruptible-nvidia.py index f50667267..a5a477ba0 100644 --- a/examples/foundational/07r-interruptible-nvidia.py +++ b/examples/foundational/07r-interruptible-nvidia.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.nvidia.llm import NvidiaLLMService +from pipecat.services.nvidia.llm import NvidiaLLMService, NvidiaLLMSettings from pipecat.services.nvidia.stt import NvidiaSTTService from pipecat.services.nvidia.tts import NvidiaTTSService from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -56,8 +56,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = NvidiaLLMService( api_key=os.getenv("NVIDIA_API_KEY"), - model="meta/llama-3.3-70b-instruct", - system_instruction="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.", + settings=NvidiaLLMSettings( + model="meta/llama-3.3-70b-instruct", + system_instruction="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.", + ), ) tts = NvidiaTTSService(api_key=os.getenv("NVIDIA_API_KEY")) diff --git a/examples/foundational/07s-interruptible-google-audio-in.py b/examples/foundational/07s-interruptible-google-audio-in.py index 1de374a3f..d4067b620 100644 --- a/examples/foundational/07s-interruptible-google-audio-in.py +++ b/examples/foundational/07s-interruptible-google-audio-in.py @@ -36,8 +36,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.google.llm import GoogleLLMService -from pipecat.services.google.tts import GoogleTTSService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.google.tts import GoogleTTSService, GoogleTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -216,7 +216,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - model="gemini-2.5-flash", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + ), # force a certain amount of thinking if you want it # params=GoogleLLMService.InputParams( # thinking=GoogleLLMService.ThinkingConfig(thinking_budget=4096) @@ -224,7 +226,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tts = GoogleTTSService( - voice_id="en-US-Chirp3-HD-Charon", + settings=GoogleTTSSettings( + voice="en-US-Chirp3-HD-Charon", + language=Language.EN_US, + ), params=GoogleTTSService.InputParams(language=Language.EN_US), credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), ) diff --git a/examples/foundational/07t-interruptible-fish.py b/examples/foundational/07t-interruptible-fish.py index 8b4152103..4825c3110 100644 --- a/examples/foundational/07t-interruptible-fish.py +++ b/examples/foundational/07t-interruptible-fish.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.fish.tts import FishAudioTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.fish.tts import FishAudioTTSService, FishAudioTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = FishAudioTTSService( api_key=os.getenv("FISH_API_KEY"), - model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama + settings=FishAudioTTSSettings( + model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07v-interruptible-neuphonic-http.py b/examples/foundational/07v-interruptible-neuphonic-http.py index 60a08e623..5c2934fcd 100644 --- a/examples/foundational/07v-interruptible-neuphonic-http.py +++ b/examples/foundational/07v-interruptible-neuphonic-http.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.neuphonic.tts import NeuphonicHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.neuphonic.tts import NeuphonicHttpTTSService, NeuphonicTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -60,13 +60,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = NeuphonicHttpTTSService( api_key=os.getenv("NEUPHONIC_API_KEY"), - voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily + settings=NeuphonicTTSSettings( + voice="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07v-interruptible-neuphonic.py b/examples/foundational/07v-interruptible-neuphonic.py index 02d6862a8..d70b187a7 100644 --- a/examples/foundational/07v-interruptible-neuphonic.py +++ b/examples/foundational/07v-interruptible-neuphonic.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.neuphonic.tts import NeuphonicTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.neuphonic.tts import NeuphonicTTSService, NeuphonicTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = NeuphonicTTSService( api_key=os.getenv("NEUPHONIC_API_KEY"), - voice_id="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily + settings=NeuphonicTTSSettings( + voice="fc854436-2dac-4d21-aa69-ae17b54e98eb", # Emily + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07w-interruptible-fal.py b/examples/foundational/07w-interruptible-fal.py index 6d88e8624..6539cbfc9 100644 --- a/examples/foundational/07w-interruptible-fal.py +++ b/examples/foundational/07w-interruptible-fal.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.fal.stt import FalSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -62,12 +62,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07x-interruptible-local.py b/examples/foundational/07x-interruptible-local.py index 3465f67b2..e0eeee03b 100644 --- a/examples/foundational/07x-interruptible-local.py +++ b/examples/foundational/07x-interruptible-local.py @@ -21,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.local.audio import LocalAudioTransport, LocalAudioTransportParams load_dotenv(override=True) @@ -44,12 +44,16 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful LLM. 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.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful LLM. 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() diff --git a/examples/foundational/07y-interruptible-minimax.py b/examples/foundational/07y-interruptible-minimax.py index f23d86f34..1213291e0 100644 --- a/examples/foundational/07y-interruptible-minimax.py +++ b/examples/foundational/07y-interruptible-minimax.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.minimax.tts import MiniMaxHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.minimax.tts import MiniMaxHttpTTSService, MiniMaxTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -63,12 +63,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): api_key=os.getenv("MINIMAX_API_KEY", ""), group_id=os.getenv("MINIMAX_GROUP_ID", ""), aiohttp_session=session, - params=MiniMaxHttpTTSService.InputParams(language=Language.EN), + settings=MiniMaxTTSSettings( + language=Language.EN, + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07z-interruptible-sarvam-http.py b/examples/foundational/07z-interruptible-sarvam-http.py index 1f9a8a4e3..566cea75a 100644 --- a/examples/foundational/07z-interruptible-sarvam-http.py +++ b/examples/foundational/07z-interruptible-sarvam-http.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.sarvam.stt import SarvamSTTService -from pipecat.services.sarvam.tts import SarvamHttpTTSService +from pipecat.services.sarvam.tts import SarvamHttpTTSService, SarvamHttpTTSSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -65,12 +65,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = SarvamHttpTTSService( api_key=os.getenv("SARVAM_API_KEY"), aiohttp_session=session, - params=SarvamHttpTTSService.InputParams(language=Language.EN), + settings=SarvamHttpTTSSettings( + language=Language.EN, + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07z-interruptible-sarvam.py b/examples/foundational/07z-interruptible-sarvam.py index a9a03e7d4..827ce947f 100644 --- a/examples/foundational/07z-interruptible-sarvam.py +++ b/examples/foundational/07z-interruptible-sarvam.py @@ -21,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.sarvam.stt import SarvamSTTService -from pipecat.services.sarvam.tts import SarvamTTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.sarvam.stt import SarvamSTTService, SarvamSTTSettings +from pipecat.services.sarvam.tts import SarvamTTSService, SarvamTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,17 +54,23 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = SarvamSTTService( api_key=os.getenv("SARVAM_API_KEY"), - model="saarika:v2.5", + settings=SarvamSTTSettings( + model="saarika:v2.5", + ), ) tts = SarvamTTSService( api_key=os.getenv("SARVAM_API_KEY"), - model="bulbul:v2", - voice_id="manisha", + settings=SarvamTTSSettings( + model="bulbul:v2", + voice="manisha", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07za-interruptible-soniox.py b/examples/foundational/07za-interruptible-soniox.py index f2d651e5b..380033a11 100644 --- a/examples/foundational/07za-interruptible-soniox.py +++ b/examples/foundational/07za-interruptible-soniox.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.soniox.stt import SonioxInputParams, SonioxSTTService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.soniox.stt import SonioxSTTService, SonioxSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -51,22 +51,28 @@ transport_params = { async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") - stt = SonioxSTTService( - api_key=os.getenv("SONIOX_API_KEY"), - params=SonioxInputParams( - language_hints=[Language.EN], - language_hints_strict=True, + stt = ( + SonioxSTTService( + api_key=os.getenv("SONIOX_API_KEY"), + settings=SonioxSTTSettings( + language_hints=[Language.EN], + language_hints_strict=True, + ), ), ) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zb-interruptible-inworld-http.py b/examples/foundational/07zb-interruptible-inworld-http.py index 9ef465781..1376ab8da 100644 --- a/examples/foundational/07zb-interruptible-inworld-http.py +++ b/examples/foundational/07zb-interruptible-inworld-http.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.inworld.tts import InworldHttpTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.inworld.tts import InworldHttpTTSService, InworldTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_output import BaseOutputTransport from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -58,15 +58,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = InworldHttpTTSService( api_key=os.getenv("INWORLD_API_KEY", ""), aiohttp_session=session, - voice_id="Ashley", - model="inworld-tts-1", - # Set to False for non-streaming mode or True for streaming mode. streaming=True, + settings=InworldTTSSettings( + voice="Ashley", + model="inworld-tts-1", + ), + # Set to False for non-streaming mode or True for streaming mode. ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful AI demonstrating Inworld AI's TTS. 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 friendly and helpful way.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful AI demonstrating Inworld AI's TTS. 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 friendly and helpful way.", + ), ) context = LLMContext() diff --git a/examples/foundational/07zb-interruptible-inworld.py b/examples/foundational/07zb-interruptible-inworld.py index 7cdbfd88a..9c9895ca9 100644 --- a/examples/foundational/07zb-interruptible-inworld.py +++ b/examples/foundational/07zb-interruptible-inworld.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.inworld.tts import InworldTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.inworld.tts import InworldTTSService, InworldTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_output import BaseOutputTransport from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,14 +56,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = InworldTTSService( api_key=os.getenv("INWORLD_API_KEY", ""), - voice_id="Ashley", - model="inworld-tts-1", - temperature=1.1, + settings=InworldTTSSettings( + voice="Ashley", + model="inworld-tts-1", + temperature=1.1, + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful AI demonstrating Inworld AI's TTS. 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 friendly and helpful way.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful AI demonstrating Inworld AI's TTS. 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 friendly and helpful way.", + ), ) context = LLMContext() diff --git a/examples/foundational/07zc-interruptible-asyncai-http.py b/examples/foundational/07zc-interruptible-asyncai-http.py index 17d187ac8..b3f46f671 100644 --- a/examples/foundational/07zc-interruptible-asyncai-http.py +++ b/examples/foundational/07zc-interruptible-asyncai-http.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.asyncai.tts import AsyncAIHttpTTSService +from pipecat.services.asyncai.tts import AsyncAIHttpTTSService, AsyncAITTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -60,13 +60,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AsyncAIHttpTTSService( api_key=os.getenv("ASYNCAI_API_KEY", ""), - voice_id=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04"), + settings=AsyncAITTSSettings( + voice="e0f39dc4-f691-4e78-bba5-5c636692cc04", + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zc-interruptible-asyncai.py b/examples/foundational/07zc-interruptible-asyncai.py index 799842658..b95a55ddb 100644 --- a/examples/foundational/07zc-interruptible-asyncai.py +++ b/examples/foundational/07zc-interruptible-asyncai.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.asyncai.tts import AsyncAITTSService +from pipecat.services.asyncai.tts import AsyncAITTSService, AsyncAITTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AsyncAITTSService( api_key=os.getenv("ASYNCAI_API_KEY", ""), - voice_id=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04"), + settings=AsyncAITTSSettings( + voice="e0f39dc4-f691-4e78-bba5-5c636692cc04", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zd-interruptible-aicoustics.py b/examples/foundational/07zd-interruptible-aicoustics.py index 9e9f6ddd6..481e098a2 100644 --- a/examples/foundational/07zd-interruptible-aicoustics.py +++ b/examples/foundational/07zd-interruptible-aicoustics.py @@ -25,9 +25,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -77,12 +77,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07ze-interruptible-hume.py b/examples/foundational/07ze-interruptible-hume.py index 395aa75d4..c5c352232 100644 --- a/examples/foundational/07ze-interruptible-hume.py +++ b/examples/foundational/07ze-interruptible-hume.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( 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.services.hume.tts import HUME_SAMPLE_RATE, HumeTTSService, HumeTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_output import BaseOutputTransport from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -59,12 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = HumeTTSService( api_key=os.getenv("HUME_API_KEY"), # Replace with your Hume voice ID - voice_id="f898a92e-685f-43fa-985b-a46920f0650b", + settings=HumeTTSSettings( + voice="f898a92e-685f-43fa-985b-a46920f0650b", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zf-interruptible-gradium.py b/examples/foundational/07zf-interruptible-gradium.py index d76735897..acf168f13 100644 --- a/examples/foundational/07zf-interruptible-gradium.py +++ b/examples/foundational/07zf-interruptible-gradium.py @@ -21,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.gradium.stt import GradiumSTTService -from pipecat.services.gradium.tts import GradiumTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.gradium.stt import GradiumSTTService, GradiumSTTSettings +from pipecat.services.gradium.tts import GradiumTTSService, GradiumTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,20 +55,24 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GradiumSTTService( api_key=os.getenv("GRADIUM_API_KEY"), api_endpoint_base_url="wss://us.api.gradium.ai/api/speech/asr", - params=GradiumSTTService.InputParams( + settings=GradiumSTTSettings( language=Language.EN, ), ) tts = GradiumTTSService( api_key=os.getenv("GRADIUM_API_KEY"), - voice_id="YTpq7expH9539ERJ", url="wss://us.api.gradium.ai/api/speech/tts", + settings=GradiumTTSSettings( + voice="YTpq7expH9539ERJ", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zg-interruptible-camb.py b/examples/foundational/07zg-interruptible-camb.py index 669315603..e8d5011e2 100644 --- a/examples/foundational/07zg-interruptible-camb.py +++ b/examples/foundational/07zg-interruptible-camb.py @@ -21,9 +21,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.camb.tts import CambTTSService +from pipecat.services.camb.tts import CambTTSService, CambTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CambTTSService( api_key=os.getenv("CAMB_API_KEY"), - model="mars-flash", + settings=CambTTSSettings( + model="mars-flash", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful voice assistant powered by Camb AI text-to-speech. ", + settings=OpenAILLMSettings( + system_instruction="You are a helpful voice assistant powered by Camb AI text-to-speech. ", + ), ) context = LLMContext() diff --git a/examples/foundational/07zi-interruptible-piper.py b/examples/foundational/07zi-interruptible-piper.py index 9d07f9cdf..9ac672fc2 100644 --- a/examples/foundational/07zi-interruptible-piper.py +++ b/examples/foundational/07zi-interruptible-piper.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.piper.tts import PiperTTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.piper.tts import PiperTTSService, PiperTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,11 +54,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = PiperTTSService(voice_id="en_US-ryan-high") + tts = PiperTTSService( + settings=PiperTTSSettings( + voice="en_US-ryan-high", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zj-interruptible-kokoro.py b/examples/foundational/07zj-interruptible-kokoro.py index 04ab90145..66a225d35 100644 --- a/examples/foundational/07zj-interruptible-kokoro.py +++ b/examples/foundational/07zj-interruptible-kokoro.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.kokoro.tts import KokoroTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.kokoro.tts import KokoroTTSService, KokoroTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,11 +54,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = KokoroTTSService(voice_id="af_heart") + tts = KokoroTTSService( + settings=KokoroTTSSettings( + voice="af_heart", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/07zk-interruptible-resemble.py b/examples/foundational/07zk-interruptible-resemble.py index d9298815d..2212fa80f 100644 --- a/examples/foundational/07zk-interruptible-resemble.py +++ b/examples/foundational/07zk-interruptible-resemble.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.resembleai.tts import ResembleAITTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.resembleai.tts import ResembleAITTSService, ResembleAITTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,12 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ResembleAITTSService( api_key=os.getenv("RESEMBLE_API_KEY"), - voice_id=os.getenv("RESEMBLE_VOICE_UUID"), + settings=ResembleAITTSSettings( + voice=os.getenv("RESEMBLE_VOICE_UUID"), + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/08-custom-frame-processor.py b/examples/foundational/08-custom-frame-processor.py index a4b5b2127..820659207 100644 --- a/examples/foundational/08-custom-frame-processor.py +++ b/examples/foundational/08-custom-frame-processor.py @@ -26,9 +26,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -95,12 +95,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/10-wake-phrase.py b/examples/foundational/10-wake-phrase.py index 52a7d1225..de237659a 100644 --- a/examples/foundational/10-wake-phrase.py +++ b/examples/foundational/10-wake-phrase.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.filters.wake_check_filter import WakeCheckFilter from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful assistant. Respond to what the user said in a creative and helpful way. Keep your responses brief.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful assistant. Respond to what the user said in a creative and helpful way. Keep your responses brief.", + ), ) hey_robot_filter = WakeCheckFilter(["hey robot", "hey, robot"]) diff --git a/examples/foundational/11-sound-effects.py b/examples/foundational/11-sound-effects.py index 401c36b8e..664bd122c 100644 --- a/examples/foundational/11-sound-effects.py +++ b/examples/foundational/11-sound-effects.py @@ -30,9 +30,9 @@ from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.logger import FrameLogger from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -106,12 +106,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) context = LLMContext() diff --git a/examples/foundational/12-describe-image-openai.py b/examples/foundational/12-describe-image-openai.py index dc45451fe..d9b0be871 100644 --- a/examples/foundational/12-describe-image-openai.py +++ b/examples/foundational/12-describe-image-openai.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -53,12 +53,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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. You are also able to describe images.", + settings=OpenAILLMSettings( + system_instruction="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. You are also able to describe images.", + ), ) context = LLMContext() diff --git a/examples/foundational/12a-describe-image-anthropic.py b/examples/foundational/12a-describe-image-anthropic.py index a1151ddf9..5a10f24a5 100644 --- a/examples/foundational/12a-describe-image-anthropic.py +++ b/examples/foundational/12a-describe-image-anthropic.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -53,12 +53,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AnthropicLLMService( api_key=os.getenv("ANTHROPIC_API_KEY"), - system_instruction="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. You are also able to describe images.", + settings=AnthropicLLMSettings( + system_instruction="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. You are also able to describe images.", + ), ) context = LLMContext() diff --git a/examples/foundational/12b-describe-image-aws.py b/examples/foundational/12b-describe-image-aws.py index 43a6ae232..eaa5e3d19 100644 --- a/examples/foundational/12b-describe-image-aws.py +++ b/examples/foundational/12b-describe-image-aws.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.aws.llm import AWSBedrockLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -53,17 +53,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AWSBedrockLLMService( aws_region="us-west-2", - model="us.anthropic.claude-3-7-sonnet-20250219-v1:0", - # Note: usually, prefer providing latency="optimized" param. - # Here we can't because AWS Bedrock doesn't support it for Claude 3.7, - # which we need for image input. - params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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. You are also able to describe images.", + settings=AWSBedrockLLMSettings( + model="us.anthropic.claude-3-7-sonnet-20250219-v1:0", + # Note: usually, prefer providing latency="optimized" param. + # Here we can't because AWS Bedrock doesn't support it for Claude 3.7, + # which we need for image input. + params=AWSBedrockLLMService.InputParams(temperature=0.8), + system_instruction="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. You are also able to describe images.", + ), ) context = LLMContext() diff --git a/examples/foundational/12c-describe-image-gemini-flash.py b/examples/foundational/12c-describe-image-gemini-flash.py index 9adbe62d2..2e76eff19 100644 --- a/examples/foundational/12c-describe-image-gemini-flash.py +++ b/examples/foundational/12c-describe-image-gemini-flash.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -53,12 +53,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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. You are also able to describe images.", + settings=GoogleLLMSettings( + system_instruction="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. You are also able to describe images.", + ), ) context = LLMContext() diff --git a/examples/foundational/12d-describe-image-moondream.py b/examples/foundational/12d-describe-image-moondream.py index 070b004a1..21fc79ed5 100644 --- a/examples/foundational/12d-describe-image-moondream.py +++ b/examples/foundational/12d-describe-image-moondream.py @@ -17,7 +17,7 @@ from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.moondream.vision import MoondreamService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -42,7 +42,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) vision = MoondreamService() diff --git a/examples/foundational/13b-deepgram-transcription.py b/examples/foundational/13b-deepgram-transcription.py index ed83bd1d5..61ba5c266 100644 --- a/examples/foundational/13b-deepgram-transcription.py +++ b/examples/foundational/13b-deepgram-transcription.py @@ -16,7 +16,7 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.deepgram.stt import DeepgramSTTService, Language, LiveOptions +from pipecat.services.deepgram.stt import DeepgramSTTService, DeepgramSTTSettings, Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -49,7 +49,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService( api_key=os.getenv("DEEPGRAM_API_KEY"), - live_options=LiveOptions(language=Language.EN), + settings=DeepgramSTTSettings( + language=Language.EN, + ), ) tl = TranscriptionLogger() diff --git a/examples/foundational/13c-gladia-transcription.py b/examples/foundational/13c-gladia-transcription.py index c98fda727..8771cb8d4 100644 --- a/examples/foundational/13c-gladia-transcription.py +++ b/examples/foundational/13c-gladia-transcription.py @@ -50,7 +50,11 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GladiaSTTService( api_key=os.getenv("GLADIA_API_KEY"), region=os.getenv("GLADIA_REGION"), - # live_options=LiveOptions(language=Language.FR), + # settings=GladiaSTTSettings( + # language_config=LanguageConfig( + # languages=[Language.FR], + # ), + # ), ) tl = TranscriptionLogger() diff --git a/examples/foundational/13c-gladia-translation.py b/examples/foundational/13c-gladia-translation.py index edc294858..9f7b6a6da 100644 --- a/examples/foundational/13c-gladia-translation.py +++ b/examples/foundational/13c-gladia-translation.py @@ -22,7 +22,7 @@ from pipecat.services.gladia.config import ( RealtimeProcessingConfig, TranslationConfig, ) -from pipecat.services.gladia.stt import GladiaSTTService +from pipecat.services.gladia.stt import GladiaSTTService, GladiaSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -59,16 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GladiaSTTService( api_key=os.getenv("GLADIA_API_KEY"), region=os.getenv("GLADIA_REGION"), - params=GladiaInputParams( + settings=GladiaSTTSettings( language_config=LanguageConfig( - languages=[Language.EN], # Input in English + languages=[Language.EN], code_switching=False, ), realtime_processing=RealtimeProcessingConfig( - translation=True, # Enable translation + translation=True, translation_config=TranslationConfig( - target_languages=[Language.ES], # Translate to Spanish - model="enhanced", # Use the enhanced translation model + target_languages=[Language.ES], + model="enhanced", ), ), ), diff --git a/examples/foundational/13d-assemblyai-transcription.py b/examples/foundational/13d-assemblyai-transcription.py index 2dcbaf59b..c4ca9cd6b 100644 --- a/examples/foundational/13d-assemblyai-transcription.py +++ b/examples/foundational/13d-assemblyai-transcription.py @@ -16,8 +16,7 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.assemblyai.models import AssemblyAIConnectionParams -from pipecat.services.assemblyai.stt import AssemblyAISTTService +from pipecat.services.assemblyai.stt import AssemblyAISTTService, AssemblyAISTTSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -50,8 +49,8 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = AssemblyAISTTService( api_key=os.getenv("ASSEMBLYAI_API_KEY"), - connection_params=AssemblyAIConnectionParams( - speech_model="u3-rt-pro", + settings=AssemblyAISTTSettings( + model="u3-rt-pro", ), ) diff --git a/examples/foundational/13e-whisper-mlx.py b/examples/foundational/13e-whisper-mlx.py index ba90d0850..0f11d4397 100644 --- a/examples/foundational/13e-whisper-mlx.py +++ b/examples/foundational/13e-whisper-mlx.py @@ -18,7 +18,7 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.whisper.stt import MLXModel, WhisperSTTServiceMLX +from pipecat.services.whisper.stt import MLXModel, WhisperMLXSTTSettings, WhisperSTTServiceMLX from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -77,7 +77,11 @@ transport_params = { async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") - stt = WhisperSTTServiceMLX(model=MLXModel.LARGE_V3_TURBO) + stt = WhisperSTTServiceMLX( + settings=WhisperMLXSTTSettings( + model=MLXModel.LARGE_V3_TURBO, + ), + ) tl = TranscriptionLogger() diff --git a/examples/foundational/13g-sambanova-transcription.py b/examples/foundational/13g-sambanova-transcription.py index cebeea615..1e399c38f 100644 --- a/examples/foundational/13g-sambanova-transcription.py +++ b/examples/foundational/13g-sambanova-transcription.py @@ -19,7 +19,7 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.sambanova.stt import SambaNovaSTTService +from pipecat.services.sambanova.stt import SambaNovaSTTService, SambaNovaSTTSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -79,7 +79,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Starting bot") stt = SambaNovaSTTService( - model="Whisper-Large-v3", + settings=SambaNovaSTTSettings( + model="Whisper-Large-v3", + ), api_key=os.getenv("SAMBANOVA_API_KEY"), ) diff --git a/examples/foundational/13h-speechmatics-transcription.py b/examples/foundational/13h-speechmatics-transcription.py index f1d1d93c6..d013357f6 100644 --- a/examples/foundational/13h-speechmatics-transcription.py +++ b/examples/foundational/13h-speechmatics-transcription.py @@ -16,7 +16,7 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.speechmatics.stt import SpeechmaticsSTTService +from pipecat.services.speechmatics.stt import SpeechmaticsSTTService, SpeechmaticsSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -65,7 +65,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = SpeechmaticsSTTService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - params=SpeechmaticsSTTService.InputParams( + settings=SpeechmaticsSTTSettings( language=Language.EN, speaker_active_format="<{speaker_id}>{text}", ), diff --git a/examples/foundational/13l-gradium-transcription.py b/examples/foundational/13l-gradium-transcription.py index 38709dff7..84b23017c 100644 --- a/examples/foundational/13l-gradium-transcription.py +++ b/examples/foundational/13l-gradium-transcription.py @@ -16,7 +16,7 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.gradium.stt import GradiumSTTService +from pipecat.services.gradium.stt import GradiumSTTService, GradiumSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -52,7 +52,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = GradiumSTTService( api_key=os.getenv("GRADIUM_API_KEY"), api_endpoint_base_url="wss://us.api.gradium.ai/api/speech/asr", - params=GradiumSTTService.InputParams(language=Language.EN, delay_in_frames=8), + settings=GradiumSTTSettings( + language=Language.EN, + delay_in_frames=8, + ), ) tl = TranscriptionLogger() diff --git a/examples/foundational/13m-openai-transcription.py b/examples/foundational/13m-openai-transcription.py index 2ef35cb3f..8dc9e0101 100644 --- a/examples/foundational/13m-openai-transcription.py +++ b/examples/foundational/13m-openai-transcription.py @@ -18,7 +18,7 @@ from pipecat.pipeline.task import PipelineTask from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.openai.stt import OpenAIRealtimeSTTService +from pipecat.services.openai.stt import OpenAIRealtimeSTTService, OpenAIRealtimeSTTSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -53,8 +53,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = OpenAIRealtimeSTTService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-transcribe", - prompt="Expect words related to dogs, such as breed names.", + settings=OpenAIRealtimeSTTSettings( + model="gpt-4o-transcribe", + prompt="Expect words related to dogs, such as breed names.", + ), ) tl = TranscriptionLogger() diff --git a/examples/foundational/14-function-calling.py b/examples/foundational/14-function-calling.py index 0087af9fc..81cddec90 100644 --- a/examples/foundational/14-function-calling.py +++ b/examples/foundational/14-function-calling.py @@ -23,10 +23,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -67,12 +67,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14a-function-calling-anthropic.py b/examples/foundational/14a-function-calling-anthropic.py index 36030bc2b..19bc314b8 100644 --- a/examples/foundational/14a-function-calling-anthropic.py +++ b/examples/foundational/14a-function-calling-anthropic.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -69,10 +69,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = AnthropicLLMService(api_key=os.getenv("ANTHROPIC_API_KEY")) + llm = AnthropicLLMService( + api_key=os.getenv("ANTHROPIC_API_KEY"), + settings=AnthropicLLMSettings( + system_instruction="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.", + ), + ) llm.register_function("get_weather", get_weather) llm.register_function("get_restaurant_recommendation", fetch_restaurant_recommendation) @@ -100,16 +107,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tools = ToolsSchema(standard_tools=[weather_function, restaurant_function]) - # todo: test with very short initial user message - - # messages = [{"role": "system", - # "content": "You are a helpful assistant who can report the weather in any location in the universe. Respond concisely. Your response will be turned into speech so use only simple words and punctuation."}, - # {"role": "user", - # "content": " Start the conversation by introducing yourself."}] - - messages = [{"role": "user", "content": "Say 'hello' to start the conversation."}] - - context = LLMContext(messages, tools) + context = LLMContext(tools=tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/14c-function-calling-together.py b/examples/foundational/14c-function-calling-together.py index 214d6f292..66ed02c15 100644 --- a/examples/foundational/14c-function-calling-together.py +++ b/examples/foundational/14c-function-calling-together.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.together.llm import TogetherLLMService +from pipecat.services.together.llm import TogetherLLMService, TogetherLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -64,13 +64,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = TogetherLLMService( api_key=os.getenv("TOGETHER_API_KEY"), - model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", - system_instruction="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.", + settings=TogetherLLMSettings( + model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14d-function-calling-anthropic-video.py b/examples/foundational/14d-function-calling-anthropic-video.py index cddde3647..f1e097902 100644 --- a/examples/foundational/14d-function-calling-anthropic-video.py +++ b/examples/foundational/14d-function-calling-anthropic-video.py @@ -28,8 +28,8 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -90,13 +90,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # Anthropic for vision analysis llm = AnthropicLLMService( api_key=os.getenv("ANTHROPIC_API_KEY"), - system_instruction="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. You are able to describe images from the user camera.", + settings=AnthropicLLMSettings( + system_instruction="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. You are able to describe images from the user camera.", + ), ) llm.register_function("fetch_user_image", fetch_user_image) diff --git a/examples/foundational/14d-function-calling-aws-video.py b/examples/foundational/14d-function-calling-aws-video.py index 396ea0a32..09ceaedd4 100644 --- a/examples/foundational/14d-function-calling-aws-video.py +++ b/examples/foundational/14d-function-calling-aws-video.py @@ -28,8 +28,8 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.aws.llm import AWSBedrockLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -90,18 +90,22 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # AWS for vision analysis llm = AWSBedrockLLMService( aws_region="us-west-2", - model="us.anthropic.claude-3-7-sonnet-20250219-v1:0", - # Note: usually, prefer providing latency="optimized" param. - # Here we can't because AWS Bedrock doesn't support it for Claude 3.7, - # which we need for image input. - params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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. You are able to describe images from the user camera.", + settings=AWSBedrockLLMSettings( + model="us.anthropic.claude-3-7-sonnet-20250219-v1:0", + # Note: usually, prefer providing latency="optimized" param. + # Here we can't because AWS Bedrock doesn't support it for Claude 3.7, + # which we need for image input. + temperature=0.8, + system_instruction="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. You are able to describe images from the user camera.", + ), ) llm.register_function("fetch_user_image", fetch_user_image) diff --git a/examples/foundational/14d-function-calling-gemini-flash-video.py b/examples/foundational/14d-function-calling-gemini-flash-video.py index c59767406..a56349f96 100644 --- a/examples/foundational/14d-function-calling-gemini-flash-video.py +++ b/examples/foundational/14d-function-calling-gemini-flash-video.py @@ -28,9 +28,9 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -90,13 +90,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # Google Gemini model for vision analysis llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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. You are able to describe images from the user camera.", + settings=GoogleLLMSettings( + system_instruction="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. You are able to describe images from the user camera.", + ), ) llm.register_function("fetch_user_image", fetch_user_image) diff --git a/examples/foundational/14d-function-calling-moondream-video.py b/examples/foundational/14d-function-calling-moondream-video.py index d0913e3dc..c32bf3549 100644 --- a/examples/foundational/14d-function-calling-moondream-video.py +++ b/examples/foundational/14d-function-calling-moondream-video.py @@ -37,11 +37,11 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.services.moondream.vision import MoondreamService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -121,12 +121,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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. You are able to describe images from the user camera.", + settings=OpenAILLMSettings( + system_instruction="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. You are able to describe images from the user camera.", + ), ) llm.register_function("fetch_user_image", fetch_user_image) diff --git a/examples/foundational/14d-function-calling-openai-video.py b/examples/foundational/14d-function-calling-openai-video.py index 50365eb29..5bfa336aa 100644 --- a/examples/foundational/14d-function-calling-openai-video.py +++ b/examples/foundational/14d-function-calling-openai-video.py @@ -29,10 +29,10 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -91,12 +91,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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. You are able to describe images from the user camera.", + settings=OpenAILLMSettings( + system_instruction="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. You are able to describe images from the user camera.", + ), ) llm.register_function("fetch_user_image", fetch_user_image) diff --git a/examples/foundational/14e-function-calling-google.py b/examples/foundational/14e-function-calling-google.py index cae32146e..19a0392b9 100644 --- a/examples/foundational/14e-function-calling-google.py +++ b/examples/foundational/14e-function-calling-google.py @@ -29,9 +29,9 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -100,10 +100,36 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY")) + system_prompt = """\ +You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions. + +Your response will be turned into speech so use only simple words and punctuation. + +You have access to three tools: get_weather, get_restaurant_recommendation, and get_image. + +You can respond to questions about the weather using the get_weather tool. + +You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \ +indicate you should use the get_image tool are: +- What do you see? +- What's in the video? +- Can you describe the video? +- Tell me about what you see. +- Tell me something interesting about what you see. +- What's happening in the video? +""" + + llm = GoogleLLMService( + api_key=os.getenv("GOOGLE_API_KEY"), + settings=GoogleLLMSettings( + system_instruction=system_prompt, + ), + ) llm.register_function("get_weather", get_weather) llm.register_function("get_image", get_image) llm.register_function("get_restaurant_recommendation", fetch_restaurant_recommendation) @@ -156,29 +182,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tools = ToolsSchema(standard_tools=[weather_function, get_image_function, restaurant_function]) - system_prompt = """\ -You are a helpful assistant who converses with a user and answers questions. Respond concisely to general questions. - -Your response will be turned into speech so use only simple words and punctuation. - -You have access to three tools: get_weather, get_restaurant_recommendation, and get_image. - -You can respond to questions about the weather using the get_weather tool. - -You can answer questions about the user's video stream using the get_image tool. Some examples of phrases that \ -indicate you should use the get_image tool are: -- What do you see? -- What's in the video? -- Can you describe the video? -- Tell me about what you see. -- Tell me something interesting about what you see. -- What's happening in the video? -""" - messages = [ - {"role": "system", "content": system_prompt}, - ] - - context = LLMContext(messages, tools) + context = LLMContext(tools=tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -214,9 +218,9 @@ indicate you should use the get_image tool are: client_id = get_transport_client_id(transport, client) # Kick off the conversation. - messages.append( + context.add_message( { - "role": "system", + "role": "user", "content": f"Please introduce yourself to the user. Use '{client_id}' as the user ID during function calls.", } ) diff --git a/examples/foundational/14f-function-calling-groq.py b/examples/foundational/14f-function-calling-groq.py index e6cfb3659..1b66e7e90 100644 --- a/examples/foundational/14f-function-calling-groq.py +++ b/examples/foundational/14f-function-calling-groq.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.groq.llm import GroqLLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.groq.llm import GroqLLMService, GroqLLMSettings from pipecat.services.groq.stt import GroqSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -64,12 +64,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GroqLLMService( api_key=os.getenv("GROQ_API_KEY"), - system_instruction="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.", + settings=GroqLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14g-function-calling-grok.py b/examples/foundational/14g-function-calling-grok.py index 51435a2a0..eb607a5b8 100644 --- a/examples/foundational/14g-function-calling-grok.py +++ b/examples/foundational/14g-function-calling-grok.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.grok.llm import GrokLLMService +from pipecat.services.grok.llm import GrokLLMService, GrokLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -64,12 +64,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GrokLLMService( api_key=os.getenv("GROK_API_KEY"), - system_instruction="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.", + settings=GrokLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14h-function-calling-azure.py b/examples/foundational/14h-function-calling-azure.py index 192cebb92..7eb3cb9de 100644 --- a/examples/foundational/14h-function-calling-azure.py +++ b/examples/foundational/14h-function-calling-azure.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.azure.llm import AzureLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.azure.llm import AzureLLMService, AzureLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -64,14 +64,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AzureLLMService( api_key=os.getenv("AZURE_CHATGPT_API_KEY"), endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), - model=os.getenv("AZURE_CHATGPT_MODEL"), - system_instruction="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.", + settings=AzureLLMSettings( + model=os.getenv("AZURE_CHATGPT_MODEL"), + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14i-function-calling-fireworks.py b/examples/foundational/14i-function-calling-fireworks.py index be006e062..aad4b6ecf 100644 --- a/examples/foundational/14i-function-calling-fireworks.py +++ b/examples/foundational/14i-function-calling-fireworks.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.fireworks.llm import FireworksLLMService +from pipecat.services.fireworks.llm import FireworksLLMService, FireworksLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -64,13 +64,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = FireworksLLMService( api_key=os.getenv("FIREWORKS_API_KEY"), - model="accounts/fireworks/models/gpt-oss-20b", - system_instruction="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.", + settings=FireworksLLMSettings( + model="accounts/fireworks/models/gpt-oss-20b", + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14j-function-calling-nvidia.py b/examples/foundational/14j-function-calling-nvidia.py index e079c228f..87c6812e8 100644 --- a/examples/foundational/14j-function-calling-nvidia.py +++ b/examples/foundational/14j-function-calling-nvidia.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.nvidia.llm import NvidiaLLMService +from pipecat.services.nvidia.llm import NvidiaLLMService, NvidiaLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -64,15 +64,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady - # text_filters=[MarkdownTextFilter()], + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = NvidiaLLMService( api_key=os.getenv("NVIDIA_API_KEY"), - model="nvidia/llama-3.3-nemotron-super-49b-v1.5", - # Recommended when turning thinking off - params=NvidiaLLMService.InputParams(temperature=0.0), + settings=NvidiaLLMSettings( + model="nvidia/llama-3.3-nemotron-super-49b-v1.5", + # Recommended when turning thinking off + temperature=0.0, + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. @@ -99,17 +103,8 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): required=["location", "format"], ) tools = ToolsSchema(standard_tools=[weather_function]) - messages = [ - # Disable thinking by sending this message first - # Check the model for the corresponding "no thinking" message - {"role": "system", "content": "/no_think"}, - { - "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, tools) + context = LLMContext(tools=tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/14k-function-calling-cerebras.py b/examples/foundational/14k-function-calling-cerebras.py index 81df8723c..4bbcf3f8e 100644 --- a/examples/foundational/14k-function-calling-cerebras.py +++ b/examples/foundational/14k-function-calling-cerebras.py @@ -24,8 +24,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.cerebras.llm import CerebrasLLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.cerebras.llm import CerebrasLLMService, CerebrasLLMSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -64,12 +64,15 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = CerebrasLLMService( api_key=os.getenv("CEREBRAS_API_KEY"), - system_instruction="""You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. + settings=CerebrasLLMSettings( + system_instruction="""You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. You have one functions available: @@ -80,6 +83,7 @@ Infer whether to use Fahrenheit or Celsius automatically based on the location, Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast. Respond to what the user said in a creative and helpful way.""", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14l-function-calling-deepseek.py b/examples/foundational/14l-function-calling-deepseek.py index 93643146a..425a58ec6 100644 --- a/examples/foundational/14l-function-calling-deepseek.py +++ b/examples/foundational/14l-function-calling-deepseek.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepseek.llm import DeepSeekLLMService +from pipecat.services.deepseek.llm import DeepSeekLLMService, DeepSeekLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -64,13 +64,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = DeepSeekLLMService( api_key=os.getenv("DEEPSEEK_API_KEY"), - model="deepseek-chat", - system_instruction="""You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. + settings=DeepSeekLLMSettings( + model="deepseek-chat", + system_instruction="""You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. You have one functions available: @@ -81,6 +84,7 @@ Infer whether to use Fahrenheit or Celsius automatically based on the location, Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast. Respond to what the user said in a creative and helpful way.""", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14m-function-calling-openrouter.py b/examples/foundational/14m-function-calling-openrouter.py index 9504021ff..fd39ef7af 100644 --- a/examples/foundational/14m-function-calling-openrouter.py +++ b/examples/foundational/14m-function-calling-openrouter.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.azure.tts import AzureTTSService +from pipecat.services.azure.tts import AzureTTSService, AzureTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openrouter.llm import OpenRouterLLMService +from pipecat.services.openrouter.llm import OpenRouterLLMService, OpenRouterLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -65,14 +65,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AzureTTSService( api_key=os.getenv("AZURE_SPEECH_API_KEY"), region=os.getenv("AZURE_SPEECH_REGION"), - voice="en-US-JennyNeural", - params=AzureTTSService.InputParams(language="en-US", rate="1.1", style="cheerful"), + settings=AzureTTSSettings( + voice="en-US-JennyNeural", + language="en-US", + rate="1.1", + style="cheerful", + ), ) llm = OpenRouterLLMService( api_key=os.getenv("OPENROUTER_API_KEY"), - model="openai/gpt-4o-2024-11-20", - system_instruction="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.", + settings=OpenRouterLLMSettings( + model="openai/gpt-4o-2024-11-20", + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14n-function-calling-perplexity.py b/examples/foundational/14n-function-calling-perplexity.py index 2f1a18d52..78d397656 100644 --- a/examples/foundational/14n-function-calling-perplexity.py +++ b/examples/foundational/14n-function-calling-perplexity.py @@ -28,9 +28,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.perplexity.llm import PerplexityLLMService +from pipecat.services.perplexity.llm import PerplexityLLMService, PerplexityLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -62,19 +62,19 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = PerplexityLLMService(api_key=os.getenv("PERPLEXITY_API_KEY")) + llm = PerplexityLLMService( + api_key=os.getenv("PERPLEXITY_API_KEY"), + settings=PerplexityLLMSettings( + system_instruction="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, but try to be brief.", + ), + ) - messages = [ - { - "role": "user", - "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, but try to be brief.", - }, - ] - - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -105,6 +105,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. + context.add_message({"role": "user", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/14o-function-calling-gemini-openai-format.py b/examples/foundational/14o-function-calling-gemini-openai-format.py index c3772eb2c..82a77e4bb 100644 --- a/examples/foundational/14o-function-calling-gemini-openai-format.py +++ b/examples/foundational/14o-function-calling-gemini-openai-format.py @@ -25,8 +25,8 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsTTSService -from pipecat.services.google.llm_openai import GoogleLLMOpenAIBetaService +from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings +from pipecat.services.google.llm_openai import GoogleLLMOpenAIBetaService, OpenAILLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -64,10 +64,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY", ""), - voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), + settings=ElevenLabsTTSSettings( + voice=os.getenv("ELEVENLABS_VOICE_ID", ""), + ), ) - llm = GoogleLLMOpenAIBetaService(api_key=os.getenv("GOOGLE_API_KEY")) + llm = GoogleLLMOpenAIBetaService( + api_key=os.getenv("GOOGLE_API_KEY"), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) # You can aslo register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. llm.register_function("get_current_weather", fetch_weather_from_api) diff --git a/examples/foundational/14p-function-calling-gemini-vertex-ai.py b/examples/foundational/14p-function-calling-gemini-vertex-ai.py index a71f3c8d1..026e41e59 100644 --- a/examples/foundational/14p-function-calling-gemini-vertex-ai.py +++ b/examples/foundational/14p-function-calling-gemini-vertex-ai.py @@ -25,8 +25,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsTTSService -from pipecat.services.google.llm_vertex import GoogleVertexLLMService +from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings +from pipecat.services.google.llm_vertex import GoogleVertexLLMService, GoogleVertexLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -64,13 +64,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY", ""), - voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), + settings=ElevenLabsTTSSettings( + voice=os.getenv("ELEVENLABS_VOICE_ID", ""), + ), ) llm = GoogleVertexLLMService( credentials=os.getenv("GOOGLE_VERTEX_TEST_CREDENTIALS"), project_id=os.getenv("GOOGLE_CLOUD_PROJECT_ID"), location=os.getenv("GOOGLE_CLOUD_LOCATION"), + settings=GoogleVertexLLMSettings( + system_instruction="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.", + ), ) # You can aslo register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14q-function-calling-qwen.py b/examples/foundational/14q-function-calling-qwen.py index 32c551b29..9aa1c3b91 100644 --- a/examples/foundational/14q-function-calling-qwen.py +++ b/examples/foundational/14q-function-calling-qwen.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.qwen.llm import QwenLLMService +from pipecat.services.qwen.llm import QwenLLMService, QwenLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -64,13 +64,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = QwenLLMService( api_key=os.getenv("QWEN_API_KEY"), model="qwen2.5-72b-instruct", - system_instruction="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.", + settings=QwenLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14r-function-calling-aws.py b/examples/foundational/14r-function-calling-aws.py index 1ce5c4220..3693cba6c 100644 --- a/examples/foundational/14r-function-calling-aws.py +++ b/examples/foundational/14r-function-calling-aws.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.aws.llm import AWSBedrockLLMService +from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings from pipecat.services.aws.stt import AWSTranscribeSTTService -from pipecat.services.aws.tts import AWSPollyTTSService +from pipecat.services.aws.tts import AWSPollyTTSService, AWSPollyTTSSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -66,15 +66,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AWSPollyTTSService( region="us-west-2", # only specific regions support generative TTS - voice_id="Joanna", - params=AWSPollyTTSService.InputParams(engine="generative", rate="1.1"), + settings=AWSPollyTTSSettings( + voice="Joanna", + engine="generative", + rate="1.1", + ), ) llm = AWSBedrockLLMService( aws_region="us-west-2", - model="us.anthropic.claude-haiku-4-5-20251001-v1:0", - params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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.", + settings=AWSBedrockLLMSettings( + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", + temperature=0.8, + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14s-function-calling-sambanova.py b/examples/foundational/14s-function-calling-sambanova.py index 1548b2aa1..46ae742f3 100644 --- a/examples/foundational/14s-function-calling-sambanova.py +++ b/examples/foundational/14s-function-calling-sambanova.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.sambanova.llm import SambaNovaLLMService +from pipecat.services.sambanova.llm import SambaNovaLLMService, SambaNovaLLMSettings from pipecat.services.sambanova.stt import SambaNovaSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -67,12 +67,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = SambaNovaLLMService( api_key=os.getenv("SAMBANOVA_API_KEY"), - system_instruction="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.", + settings=SambaNovaLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/14t-function-calling-direct.py b/examples/foundational/14t-function-calling-direct.py index 31efb7ac9..86a8d61b2 100644 --- a/examples/foundational/14t-function-calling-direct.py +++ b/examples/foundational/14t-function-calling-direct.py @@ -23,10 +23,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -80,12 +80,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14u-function-calling-ollama.py b/examples/foundational/14u-function-calling-ollama.py index b7c65dedf..761bab4a4 100644 --- a/examples/foundational/14u-function-calling-ollama.py +++ b/examples/foundational/14u-function-calling-ollama.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.ollama.llm import OLLamaLLMService +from pipecat.services.ollama.llm import OLLamaLLMService, OLLamaLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -68,12 +68,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OLLamaLLMService( - model="llama3.2", - system_instruction="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.", + settings=OLLamaLLMSettings( + model="llama3.2", + system_instruction="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.", + ), ) # Update to the model you're running locally # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14v-function-calling-openai.py b/examples/foundational/14v-function-calling-openai.py index 920275975..5e86632ec 100644 --- a/examples/foundational/14v-function-calling-openai.py +++ b/examples/foundational/14v-function-calling-openai.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.openai.stt import OpenAISTTService -from pipecat.services.openai.tts import OpenAITTSService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings +from pipecat.services.openai.stt import OpenAISTTService, OpenAISTTSettings +from pipecat.services.openai.tts import OpenAITTSService, OpenAITTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -65,22 +65,26 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = OpenAISTTService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-transcribe", - prompt="Expect words related weather, such as temperature and conditions. And restaurant names.", + settings=OpenAISTTSettings( + model="gpt-4o-transcribe", + prompt="Expect words related weather, such as temperature and conditions. And restaurant names.", + ), ) - # voice choices: ash, ballad, or any other voice available in the OpenAI TTS API - # see https://www.openai.fm/ tts = OpenAITTSService( api_key=os.getenv("OPENAI_API_KEY"), - voice="ballad", + settings=OpenAITTSSettings( + voice="ballad", + ), instructions="Please speak clearly and at a moderate pace.", ) # model choices: gpt-4o, gpt-4.1, etc. llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14w-function-calling-mistral.py b/examples/foundational/14w-function-calling-mistral.py index e17d31f72..ce535c3ef 100644 --- a/examples/foundational/14w-function-calling-mistral.py +++ b/examples/foundational/14w-function-calling-mistral.py @@ -23,10 +23,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.mistral.llm import MistralLLMService +from pipecat.services.mistral.llm import MistralLLMService, MistralLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -67,12 +67,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = MistralLLMService( api_key=os.getenv("MISTRAL_API_KEY"), - system_instruction="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.", + settings=MistralLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/14x-function-calling-openpipe.py b/examples/foundational/14x-function-calling-openpipe.py index 8a71a83d7..4f6898f5c 100644 --- a/examples/foundational/14x-function-calling-openpipe.py +++ b/examples/foundational/14x-function-calling-openpipe.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openpipe.llm import OpenPipeLLMService +from pipecat.services.openpipe.llm import OpenPipeLLMService, OpenPipeLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -68,7 +68,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) timestamp = int(time.time()) @@ -76,7 +78,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): api_key=os.getenv("OPENAI_API_KEY"), openpipe_api_key=os.getenv("OPENPIPE_API_KEY"), tags={"conversation_id": f"pipecat-{timestamp}"}, - system_instruction="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.", + settings=OpenPipeLLMSettings( + system_instruction="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.", + ), ) # You can also register a function_name of None to get all functions diff --git a/examples/foundational/15-switch-voices.py b/examples/foundational/15-switch-voices.py index 4478c067b..c298aaf0f 100644 --- a/examples/foundational/15-switch-voices.py +++ b/examples/foundational/15-switch-voices.py @@ -26,10 +26,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.filters.function_filter import FunctionFilter from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -43,17 +43,23 @@ class SwitchVoices(ParallelPipeline): news_lady = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="bf991597-6c13-47e4-8411-91ec2de5c466", # Newslady + settings=CartesiaTTSSettings( + voice="bf991597-6c13-47e4-8411-91ec2de5c466", # Newslady + ), ) british_lady = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) barbershop_man = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="a0e99841-438c-4a64-b679-ae501e7d6091", # Barbershop Man + settings=CartesiaTTSSettings( + voice="a0e99841-438c-4a64-b679-ae501e7d6091", # Barbershop Man + ), ) super().__init__( @@ -114,7 +120,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can do the following voices: 'News Lady', 'British Lady' and 'Barbershop Man'.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can do the following voices: 'News Lady', 'British Lady' and 'Barbershop Man'.", + ), ) llm.register_function("switch_voice", tts.switch_voice) diff --git a/examples/foundational/15a-switch-languages.py b/examples/foundational/15a-switch-languages.py index 3ad897077..c19038ea2 100644 --- a/examples/foundational/15a-switch-languages.py +++ b/examples/foundational/15a-switch-languages.py @@ -27,10 +27,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.filters.function_filter import FunctionFilter from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -44,12 +44,16 @@ class SwitchLanguage(ParallelPipeline): english_tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) spanish_tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady + settings=CartesiaTTSSettings( + voice="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady + ), ) super().__init__( @@ -105,7 +109,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can speak the following languages: 'English' and 'Spanish'.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities. Respond to what the user said in a creative and helpful way. Your output should not include non-alphanumeric characters. You can speak the following languages: 'English' and 'Spanish'.", + ), ) llm.register_function("switch_language", tts.switch_language) diff --git a/examples/foundational/16-gpu-container-local-bot.py b/examples/foundational/16-gpu-container-local-bot.py index 8367e1044..103b5216f 100644 --- a/examples/foundational/16-gpu-container-local-bot.py +++ b/examples/foundational/16-gpu-container-local-bot.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import ( DailyOutputTransportMessageFrame, @@ -60,7 +60,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = DeepgramTTSService( api_key=os.getenv("DEEPGRAM_API_KEY"), - voice="aura-asteria-en", + settings=DeepgramTTSSettings( + voice="aura-asteria-en", + ), base_url="http://0.0.0.0:8080", ) @@ -68,9 +70,11 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # To use OpenAI # api_key=os.getenv("OPENAI_API_KEY"), # Or, to use a local vLLM (or similar) api server - model="meta-llama/Meta-Llama-3-8B-Instruct", + settings=OpenAILLMSettings( + model="meta-llama/Meta-Llama-3-8B-Instruct", + system_instruction="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.", + ), base_url="http://0.0.0.0:8000/v1", - system_instruction="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() diff --git a/examples/foundational/17-detect-user-idle.py b/examples/foundational/17-detect-user-idle.py index 217162ea8..ecb7ceea1 100644 --- a/examples/foundational/17-detect-user-idle.py +++ b/examples/foundational/17-detect-user-idle.py @@ -32,10 +32,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -115,12 +115,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) llm.register_function("get_current_weather", fetch_weather_from_api) diff --git a/examples/foundational/19b-openai-realtime-beta-text.py b/examples/foundational/19b-openai-realtime-beta-text.py index 83e1563a0..7a4ad3469 100644 --- a/examples/foundational/19b-openai-realtime-beta-text.py +++ b/examples/foundational/19b-openai-realtime-beta-text.py @@ -21,7 +21,7 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.services.openai_realtime_beta import ( InputAudioNoiseReduction, @@ -147,7 +147,9 @@ Remember, your responses should be short. Just one or two sentences, usually. Re tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # you can either register a single function for all function calls, or specific functions diff --git a/examples/foundational/19b-openai-realtime-text.py b/examples/foundational/19b-openai-realtime-text.py index 38731d72a..98dc81c3b 100644 --- a/examples/foundational/19b-openai-realtime-text.py +++ b/examples/foundational/19b-openai-realtime-text.py @@ -22,7 +22,7 @@ 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.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.services.openai.realtime.events import ( AudioConfiguration, @@ -154,7 +154,9 @@ Remember, your responses should be short. Just one or two sentences, usually. Re tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # you can either register a single function for all function calls, or specific functions diff --git a/examples/foundational/20a-persistent-context-openai.py b/examples/foundational/20a-persistent-context-openai.py index be40add52..acdcefb92 100644 --- a/examples/foundational/20a-persistent-context-openai.py +++ b/examples/foundational/20a-persistent-context-openai.py @@ -26,7 +26,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.services.openai.llm import OpenAILLMService @@ -180,7 +180,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) diff --git a/examples/foundational/20c-persistent-context-anthropic.py b/examples/foundational/20c-persistent-context-anthropic.py index d99f4debf..5f2a3f317 100644 --- a/examples/foundational/20c-persistent-context-anthropic.py +++ b/examples/foundational/20c-persistent-context-anthropic.py @@ -27,7 +27,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -189,12 +189,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = AnthropicLLMService( - api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-5-sonnet-latest" - ) + llm = AnthropicLLMService(api_key=os.getenv("ANTHROPIC_API_KEY")) # you can either register a single function for all function calls, or specific functions # llm.register_function(None, fetch_weather_from_api) diff --git a/examples/foundational/20d-persistent-context-gemini.py b/examples/foundational/20d-persistent-context-gemini.py index 3bcd3c106..ca5186532 100644 --- a/examples/foundational/20d-persistent-context-gemini.py +++ b/examples/foundational/20d-persistent-context-gemini.py @@ -31,7 +31,7 @@ from pipecat.runner.utils import ( get_transport_client_id, maybe_capture_participant_camera, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.llm import GoogleLLMService from pipecat.services.llm_service import FunctionCallParams @@ -257,7 +257,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY")) diff --git a/examples/foundational/20e-persistent-context-aws-nova-sonic.py b/examples/foundational/20e-persistent-context-aws-nova-sonic.py index 69ffb86b6..7efa2678c 100644 --- a/examples/foundational/20e-persistent-context-aws-nova-sonic.py +++ b/examples/foundational/20e-persistent-context-aws-nova-sonic.py @@ -24,7 +24,7 @@ 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.aws.nova_sonic.llm import AWSNovaSonicLLMService +from pipecat.services.aws.nova_sonic.llm import AWSNovaSonicLLMService, AWSNovaSonicLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -222,9 +222,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"), access_key_id=os.getenv("AWS_ACCESS_KEY_ID"), region=os.getenv("AWS_REGION"), # as of 2025-05-06, us-east-1 is the only supported region - voice_id="tiffany", # matthew, tiffany, amy - # you could choose to pass instruction here rather than via context - # system_instruction=system_instruction, + settings=AWSNovaSonicLLMSettings( + voice="tiffany", # matthew, tiffany, amy + system_instruction=system_instruction, + ), # you could choose to pass tools here rather than via context # tools=tools ) @@ -236,7 +237,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): context = LLMContext( messages=[ - {"role": "system", "content": f"{system_instruction}"}, {"role": "user", "content": "Hello!"}, ], tools=tools, diff --git a/examples/foundational/21-tavus-transport.py b/examples/foundational/21-tavus-transport.py index b16ebbf38..7936a4555 100644 --- a/examples/foundational/21-tavus-transport.py +++ b/examples/foundational/21-tavus-transport.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.transports.tavus.transport import TavusParams, TavusTransport load_dotenv(override=True) @@ -51,12 +51,16 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="a167e0f3-df7e-4d52-a9c3-f949145efdab", + settings=CartesiaTTSSettings( + voice="a167e0f3-df7e-4d52-a9c3-f949145efdab", + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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.", + settings=GoogleLLMSettings( + system_instruction="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() diff --git a/examples/foundational/21a-tavus-video-service.py b/examples/foundational/21a-tavus-video-service.py index 7e32579b0..fd2ff5880 100644 --- a/examples/foundational/21a-tavus-video-service.py +++ b/examples/foundational/21a-tavus-video-service.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.tavus.video import TavusVideoService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -61,12 +61,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="a167e0f3-df7e-4d52-a9c3-f949145efdab", + settings=CartesiaTTSSettings( + voice="a167e0f3-df7e-4d52-a9c3-f949145efdab", + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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.", + settings=GoogleLLMSettings( + system_instruction="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.", + ), ) tavus = TavusVideoService( diff --git a/examples/foundational/22-filter-incomplete-turns.py b/examples/foundational/22-filter-incomplete-turns.py index b7d094d1e..6d5af6be8 100644 --- a/examples/foundational/22-filter-incomplete-turns.py +++ b/examples/foundational/22-filter-incomplete-turns.py @@ -35,9 +35,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -68,21 +68,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - messages = [ - { - "role": "system", - "content": f"""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) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams( @@ -128,9 +128,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append( + context.add_message( { - "role": "system", + "role": "user", "content": "Please introduce yourself to the user, asking them a question that will require a complete response. To start, say 'Let me start with a fun one. If you could travel anywhere in the world right now, where would you go and why?'", } ) diff --git a/examples/foundational/23-bot-background-sound.py b/examples/foundational/23-bot-background-sound.py index a57e8f446..ad82ab8c3 100644 --- a/examples/foundational/23-bot-background-sound.py +++ b/examples/foundational/23-bot-background-sound.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -75,12 +75,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/24-user-mute-strategy.py b/examples/foundational/24-user-mute-strategy.py index 36b537e6a..ab206de73 100644 --- a/examples/foundational/24-user-mute-strategy.py +++ b/examples/foundational/24-user-mute-strategy.py @@ -26,9 +26,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -71,11 +71,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) - tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en") + tts = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-2-helena-en", + ), + ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful assistant who can check the weather. Always check the weather when a location is mentioned. Respond concisely and naturally. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful assistant who can check the weather. Always check the weather when a location is mentioned. Respond concisely and naturally. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points.", + ), ) llm.register_function("get_current_weather", fetch_weather_from_api) diff --git a/examples/foundational/25-google-audio-in.py b/examples/foundational/25-google-audio-in.py index 40903e1d5..1a8d203cd 100644 --- a/examples/foundational/25-google-audio-in.py +++ b/examples/foundational/25-google-audio-in.py @@ -32,8 +32,8 @@ from pipecat.processors.aggregators.llm_response_universal import LLMContextAggr from pipecat.processors.frame_processor import FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -290,26 +290,30 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) conversation_llm = GoogleLLMService( name="Conversation", - model="gemini-2.0-flash-001", - # model="gemini-exp-1121", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + system_instruction=conversation_system_message, + ), api_key=os.getenv("GOOGLE_API_KEY"), # we can give the GoogleLLMService a system instruction to use directly # in the GenerativeModel constructor. Let's do that rather than put # our system message in the messages list. - system_instruction=conversation_system_message, ) input_transcription_llm = GoogleLLMService( name="Transcription", - model="gemini-2.0-flash-001", - # model="gemini-exp-1121", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + system_instruction=transcriber_system_message, + ), api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction=transcriber_system_message, ) messages = [ diff --git a/examples/foundational/26d-gemini-live-text.py b/examples/foundational/26d-gemini-live-text.py index 1b3845fa3..eebe9874d 100644 --- a/examples/foundational/26d-gemini-live-text.py +++ b/examples/foundational/26d-gemini-live-text.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.google.gemini_live.llm import ( GeminiLiveLLMService, GeminiModalities, diff --git a/examples/foundational/27-simli-layer.py b/examples/foundational/27-simli-layer.py index fb469fbe1..3120a1280 100644 --- a/examples/foundational/27-simli-layer.py +++ b/examples/foundational/27-simli-layer.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.simli.video import SimliVideoService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -60,7 +60,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", + ), ) simli_ai = SimliVideoService( @@ -70,8 +72,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-mini", - system_instruction="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.", + settings=OpenAILLMSettings( + model="gpt-4o-mini", + system_instruction="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() diff --git a/examples/foundational/28-user-assistant-turns.py b/examples/foundational/28-user-assistant-turns.py index 9dd1fa2a1..2a7cce980 100644 --- a/examples/foundational/28-user-assistant-turns.py +++ b/examples/foundational/28-user-assistant-turns.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -122,12 +122,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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, helpful, and brief way.", + settings=OpenAILLMSettings( + system_instruction="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, helpful, and brief way.", + ), ) context = LLMContext() diff --git a/examples/foundational/29-turn-tracking-observer.py b/examples/foundational/29-turn-tracking-observer.py index 9ba22dfda..d83442456 100644 --- a/examples/foundational/29-turn-tracking-observer.py +++ b/examples/foundational/29-turn-tracking-observer.py @@ -27,10 +27,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -73,12 +73,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) llm.register_function("get_current_weather", fetch_weather_from_api) diff --git a/examples/foundational/30-observer.py b/examples/foundational/30-observer.py index 4616e0e03..c730a2993 100644 --- a/examples/foundational/30-observer.py +++ b/examples/foundational/30-observer.py @@ -34,9 +34,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_input import BaseInputTransport from pipecat.transports.base_output import BaseOutputTransport from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -104,12 +104,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/32-gemini-grounding-metadata.py b/examples/foundational/32-gemini-grounding-metadata.py index 19844b1fa..6c2b182f7 100644 --- a/examples/foundational/32-gemini-grounding-metadata.py +++ b/examples/foundational/32-gemini-grounding-metadata.py @@ -25,9 +25,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService, LLMSearchResponseFrame +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings, LLMSearchResponseFrame from pipecat.services.llm_service import LLMService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -99,13 +99,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # Initialize the Gemini Multimodal Live model llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction=system_instruction, + settings=GoogleLLMSettings( + system_instruction=system_instruction, + ), tools=tools, ) diff --git a/examples/foundational/33-gemini-rag.py b/examples/foundational/33-gemini-rag.py index ae95ce117..3b1ba6bb9 100644 --- a/examples/foundational/33-gemini-rag.py +++ b/examples/foundational/33-gemini-rag.py @@ -69,9 +69,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -183,11 +183,24 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="f9836c6e-a0bd-460e-9d3c-f7299fa60f94", # Southern Lady + settings=CartesiaTTSSettings( + voice="f9836c6e-a0bd-460e-9d3c-f7299fa60f94", # Southern Lady + ), ) + system_prompt = """\ +You are a helpful assistant who converses with a user and answers questions. + +You have access to the tool, query_knowledge_base, that allows you to query the knowledge base for the answer to the user's question. + +Your response will be turned into speech so use only simple words and punctuation. +""" + llm = GoogleLLMService( - model=VOICE_MODEL, + settings=GoogleLLMSettings( + model=VOICE_MODEL, + system_instruction=system_prompt, + ), api_key=os.getenv("GOOGLE_API_KEY"), ) llm.register_function("query_knowledge_base", query_knowledge_base) @@ -205,15 +218,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tools = ToolsSchema(standard_tools=[query_function]) - system_prompt = """\ -You are a helpful assistant who converses with a user and answers questions. - -You have access to the tool, query_knowledge_base, that allows you to query the knowledge base for the answer to the user's question. - -Your response will be turned into speech so use only simple words and punctuation. -""" messages = [ - {"role": "system", "content": system_prompt}, {"role": "user", "content": "Greet the user."}, ] diff --git a/examples/foundational/34-audio-recording.py b/examples/foundational/34-audio-recording.py index 8435acbde..2bc413ec2 100644 --- a/examples/foundational/34-audio-recording.py +++ b/examples/foundational/34-audio-recording.py @@ -63,9 +63,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -112,13 +112,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4", - system_instruction="You are a helpful assistant demonstrating audio recording capabilities. Keep your responses brief and clear.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful assistant demonstrating audio recording capabilities. Keep your responses brief and clear.", + ), ) # Create audio buffer processor diff --git a/examples/foundational/35-pattern-pair-voice-switching.py b/examples/foundational/35-pattern-pair-voice-switching.py index cacc04459..0c5c6256c 100644 --- a/examples/foundational/35-pattern-pair-voice-switching.py +++ b/examples/foundational/35-pattern-pair-voice-switching.py @@ -56,9 +56,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -129,13 +129,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Initialize TTS with narrator voice as default tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id=VOICE_IDS["narrator"], + settings=CartesiaTTSSettings( + voice=VOICE_IDS["narrator"], + ), text_aggregator=pattern_aggregator, ) - # Initialize LLM - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) - # System prompt for storytelling with voice switching system_prompt = """You are an engaging storyteller that uses different voices to bring stories to life. @@ -184,15 +183,15 @@ FOLLOW THESE RULES: Remember: Use narrator voice for EVERYTHING except the actual quoted dialogue.""" - # Set up LLM context - messages = [ - { - "role": "system", - "content": system_prompt, - }, - ] + # Initialize LLM + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction=system_prompt, + ), + ) - context = LLMContext(messages) + context = LLMContext() user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/36-user-email-gathering.py b/examples/foundational/36-user-email-gathering.py index 95450c695..2f9c04fd8 100644 --- a/examples/foundational/36-user-email-gathering.py +++ b/examples/foundational/36-user-email-gathering.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -67,7 +67,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # (see https://docs.cartesia.ai/build-with-sonic/formatting-text-for-sonic/spelling-out-input-text) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # Rime offers a function `spell()` that we can use to ask the user @@ -75,13 +77,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # (see https://docs.rime.ai/api-reference/spell) # tts = RimeHttpTTSService( # api_key=os.getenv("RIME_API_KEY", ""), - # voice_id="eva", + # settings=RimeTTSSettings( + # voice="eva", + # ), # aiohttp_session=session, # ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You need to gather a valid email or emails from the user. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. If the user provides one or more email addresses confirm them with the user. Enclose all emails with tags, for example a@a.com.", + settings=OpenAILLMSettings( + system_instruction="You need to gather a valid email or emails from the user. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. If the user provides one or more email addresses confirm them with the user. Enclose all emails with tags, for example a@a.com.", + ), ) # You can aslo register a function_name of None to get all functions # sent to the same callback with an additional function_name parameter. diff --git a/examples/foundational/37-mem0.py b/examples/foundational/37-mem0.py index bfc651f3a..5e9dc351d 100644 --- a/examples/foundational/37-mem0.py +++ b/examples/foundational/37-mem0.py @@ -60,9 +60,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsTTSService +from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings from pipecat.services.mem0.memory import Mem0MemoryService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -166,7 +166,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Initialize text-to-speech service tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY"), - voice_id="pNInz6obpgDQGcFmaJgB", + settings=ElevenLabsTTSSettings( + voice="pNInz6obpgDQGcFmaJgB", + ), ) # ===================================================================== @@ -223,13 +225,15 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Initialize LLM service llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - model="gpt-4o-mini", - system_instruction="""You are a personal assistant. You can remember things about the person you are talking to. + settings=OpenAILLMSettings( + model="gpt-4o-mini", + system_instruction="""You are a personal assistant. You can remember things about the person you are talking to. Some Guidelines: - Make sure your responses are friendly yet short and concise. - If the user asks you to remember something, make sure to remember it. - Greet the user by their name if you know about it. """, + ), ) # Set up conversation context and management diff --git a/examples/foundational/38-smart-turn-fal.py b/examples/foundational/38-smart-turn-fal.py index fe8992784..2eafe6297 100644 --- a/examples/foundational/38-smart-turn-fal.py +++ b/examples/foundational/38-smart-turn-fal.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -61,12 +61,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/38a-smart-turn-local-coreml.py b/examples/foundational/38a-smart-turn-local-coreml.py index 166fbbe12..4ed17642b 100644 --- a/examples/foundational/38a-smart-turn-local-coreml.py +++ b/examples/foundational/38a-smart-turn-local-coreml.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -76,12 +76,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/38b-smart-turn-local.py b/examples/foundational/38b-smart-turn-local.py index 962b608da..361889a5b 100644 --- a/examples/foundational/38b-smart-turn-local.py +++ b/examples/foundational/38b-smart-turn-local.py @@ -24,9 +24,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -58,12 +58,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/39-mcp-stdio.py b/examples/foundational/39-mcp-stdio.py index 2daf21626..7e648cfd7 100644 --- a/examples/foundational/39-mcp-stdio.py +++ b/examples/foundational/39-mcp-stdio.py @@ -35,8 +35,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.mcp_service import MCPClient from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -137,11 +137,29 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) + system = f""" + You are a helpful LLM in a WebRTC call. + Your goal is to demonstrate your capabilities in a succinct way. + You have access to tools to search the Rijksmuseum collection. + Offer, for example, to show a floral still life, use the `search_artwork` tool. + The tool may respond with a JSON object with an `artworks` array. Choose the art from that array. + Once the tool has responded, tell the user the title and use the `open_image_in_browser` tool. + 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. + Don't overexplain what you are doing. + Just respond with short sentences when you are carrying out tool calls. + """ + llm = AnthropicLLMService( - api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-7-sonnet-latest" + api_key=os.getenv("ANTHROPIC_API_KEY"), + settings=AnthropicLLMSettings( + system_instruction=system, + ), ) try: @@ -169,22 +187,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.error(f"error registering tools") logger.exception("error trace:") - system = f""" - You are a helpful LLM in a WebRTC call. - Your goal is to demonstrate your capabilities in a succinct way. - You have access to tools to search the Rijksmuseum collection. - Offer, for example, to show a floral still life, use the `search_artwork` tool. - The tool may respond with a JSON object with an `artworks` array. Choose the art from that array. - Once the tool has responded, tell the user the title and use the `open_image_in_browser` tool. - 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. - Don't overexplain what you are doing. - Just respond with short sentences when you are carrying out tool calls. - """ - - messages = [{"role": "system", "content": system}] - - context = LLMContext(messages, tools) + context = LLMContext(tools=tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/39a-mcp-streamable-http.py b/examples/foundational/39a-mcp-streamable-http.py index 2af2ba9cb..870556073 100644 --- a/examples/foundational/39a-mcp-streamable-http.py +++ b/examples/foundational/39a-mcp-streamable-http.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.llm import GoogleLLMService from pipecat.services.mcp_service import MCPClient @@ -58,7 +58,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash") diff --git a/examples/foundational/39b-mcp-streamable-http-gemini-live.py b/examples/foundational/39b-mcp-streamable-http-gemini-live.py index c4c427bd8..8a0ea57fd 100644 --- a/examples/foundational/39b-mcp-streamable-http-gemini-live.py +++ b/examples/foundational/39b-mcp-streamable-http-gemini-live.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.gemini_live.llm import GeminiLiveLLMService from pipecat.services.mcp_service import MCPClient @@ -58,7 +58,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) try: diff --git a/examples/foundational/39c-multiple-mcp.py b/examples/foundational/39c-multiple-mcp.py index 5f662cdb8..e4612efa4 100644 --- a/examples/foundational/39c-multiple-mcp.py +++ b/examples/foundational/39c-multiple-mcp.py @@ -37,8 +37,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.mcp_service import MCPClient from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -120,11 +120,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady - ) - - llm = AnthropicLLMService( - api_key=os.getenv("ANTHROPIC_API_KEY"), model="claude-3-7-sonnet-latest" + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) system = f""" @@ -141,7 +139,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): Just respond with short sentences when you are carrying out tool calls. """ - messages = [{"role": "system", "content": system}] + llm = AnthropicLLMService( + api_key=os.getenv("ANTHROPIC_API_KEY"), + settings=AnthropicLLMSettings( + system_instruction=system, + ), + ) try: rijksmuseum_mcp = MCPClient( @@ -184,7 +187,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): all_standard_tools = rijksmuseum_tools.standard_tools + github_tools.standard_tools all_tools = ToolsSchema(standard_tools=all_standard_tools) - context = LLMContext(messages, all_tools) + context = LLMContext(tools=all_tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), diff --git a/examples/foundational/40-aws-nova-sonic.py b/examples/foundational/40-aws-nova-sonic.py index 1bfa6063e..0bb670d4b 100644 --- a/examples/foundational/40-aws-nova-sonic.py +++ b/examples/foundational/40-aws-nova-sonic.py @@ -28,7 +28,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.aws.nova_sonic.llm import AWSNovaSonicLLMService +from pipecat.services.aws.nova_sonic.llm import AWSNovaSonicLLMService, AWSNovaSonicLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -130,9 +130,10 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # - ap-northeast-1 region=os.getenv("AWS_REGION"), session_token=os.getenv("AWS_SESSION_TOKEN"), - voice_id="tiffany", - # you could choose to pass instruction here rather than via context - # system_instruction=system_instruction + settings=AWSNovaSonicLLMSettings( + voice="tiffany", + system_instruction=system_instruction, + ), # you could choose to pass tools here rather than via context # tools=tools ) @@ -147,7 +148,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Set up context and context management. context = LLMContext( messages=[ - {"role": "system", "content": f"{system_instruction}"}, { "role": "user", "content": "Tell me a fun fact!", diff --git a/examples/foundational/42-interruption-config.py b/examples/foundational/42-interruption-config.py index 4491f9ee0..4c8e3ba23 100644 --- a/examples/foundational/42-interruption-config.py +++ b/examples/foundational/42-interruption-config.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,12 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/43-heygen-transport.py b/examples/foundational/43-heygen-transport.py index e38cb7b6e..ad0e20764 100644 --- a/examples/foundational/43-heygen-transport.py +++ b/examples/foundational/43-heygen-transport.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams, ) -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.heygen.api_liveavatar import LiveAvatarNewSessionRequest from pipecat.transports.heygen.transport import HeyGenParams, HeyGenTransport, ServiceType @@ -56,12 +56,16 @@ async def main(): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="00967b2f-88a6-4a31-8153-110a92134b9f", + settings=CartesiaTTSSettings( + voice="00967b2f-88a6-4a31-8153-110a92134b9f", + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="You are a helpful assistant. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Be succinct and respond to what the user said in a creative and helpful way.", + settings=GoogleLLMSettings( + system_instruction="You are a helpful assistant. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Be succinct and respond to what the user said in a creative and helpful way.", + ), ) context = LLMContext() diff --git a/examples/foundational/43a-heygen-video-service.py b/examples/foundational/43a-heygen-video-service.py index 2b23fe1f8..e4bd0e460 100644 --- a/examples/foundational/43a-heygen-video-service.py +++ b/examples/foundational/43a-heygen-video-service.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.heygen.api_liveavatar import LiveAvatarNewSessionRequest from pipecat.services.heygen.client import ServiceType from pipecat.services.heygen.video import HeyGenVideoService @@ -63,12 +63,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="00967b2f-88a6-4a31-8153-110a92134b9f", + settings=CartesiaTTSSettings( + voice="00967b2f-88a6-4a31-8153-110a92134b9f", + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="You are a helpful assistant. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Be succinct and respond to what the user said in a creative and helpful way.", + settings=GoogleLLMSettings( + system_instruction="You are a helpful assistant. Your output will be spoken aloud, so avoid special characters that can't easily be spoken, such as emojis or bullet points. Be succinct and respond to what the user said in a creative and helpful way.", + ), ) heyGen = HeyGenVideoService( diff --git a/examples/foundational/44-voicemail-detection.py b/examples/foundational/44-voicemail-detection.py index f7cf14f71..ef7d73b38 100644 --- a/examples/foundational/44-voicemail-detection.py +++ b/examples/foundational/44-voicemail-detection.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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.", + ), ) classifier_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) diff --git a/examples/foundational/45-before-and-after-events.py b/examples/foundational/45-before-and-after-events.py index 405af49f3..c06837a4b 100644 --- a/examples/foundational/45-before-and-after-events.py +++ b/examples/foundational/45-before-and-after-events.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -67,12 +67,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/47-sentry-metrics.py b/examples/foundational/47-sentry-metrics.py index ef20745e4..d024ed73a 100644 --- a/examples/foundational/47-sentry-metrics.py +++ b/examples/foundational/47-sentry-metrics.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.metrics.sentry import SentryMetrics from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -66,14 +66,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), metrics=SentryMetrics(), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), metrics=SentryMetrics(), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/48-service-switcher.py b/examples/foundational/48-service-switcher.py index 4aaafa508..d0e3f09ec 100644 --- a/examples/foundational/48-service-switcher.py +++ b/examples/foundational/48-service-switcher.py @@ -27,12 +27,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.stt import CartesiaSTTService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepgram.tts import DeepgramTTSService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -102,15 +102,30 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts_cartesia = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), + ) + tts_deepgram = DeepgramTTSService( + api_key=os.getenv("DEEPGRAM_API_KEY"), + settings=DeepgramTTSSettings( + voice="aura-2-helena-en", + ), ) - tts_deepgram = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts_switcher = ServiceSwitcher( services=[tts_cartesia, tts_deepgram], strategy_type=ServiceSwitcherStrategyManual ) - llm_openai = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) - llm_google = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY")) + system = "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." + + llm_openai = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings(system_instruction=system), + ) + llm_google = GoogleLLMService( + api_key=os.getenv("GOOGLE_API_KEY"), + settings=GoogleLLMSettings(system_instruction=system), + ) llm_switcher = LLMSwitcher( llms=[llm_openai, llm_google], strategy_type=ServiceSwitcherStrategyManual ) @@ -119,15 +134,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): # Register a "direct" function llm_switcher.register_direct_function(get_restaurant_recommendation) - 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.", - }, - ] tools = ToolsSchema(standard_tools=[weather_function, get_restaurant_recommendation]) - context = LLMContext(messages, tools) + context = LLMContext(tools=tools) user_aggregator, assistant_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()), @@ -158,7 +167,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "user", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) await asyncio.sleep(15) print(f"Switching to {stt_deepgram}") diff --git a/examples/foundational/49a-thinking-anthropic.py b/examples/foundational/49a-thinking-anthropic.py index 28dd33565..a222ad19f 100644 --- a/examples/foundational/49a-thinking-anthropic.py +++ b/examples/foundational/49a-thinking-anthropic.py @@ -22,8 +22,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import ( + AnthropicLLMService, + AnthropicLLMSettings, + AnthropicThinkingConfig, +) +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,15 +60,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AnthropicLLMService( api_key=os.getenv("ANTHROPIC_API_KEY"), - params=AnthropicLLMService.InputParams( - thinking=AnthropicLLMService.ThinkingConfig(type="enabled", budget_tokens=2048) + settings=AnthropicLLMSettings( + thinking=AnthropicThinkingConfig( + type="enabled", + budget_tokens=2048, + ), + system_instruction="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.", ), - system_instruction="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() diff --git a/examples/foundational/49b-thinking-google.py b/examples/foundational/49b-thinking-google.py index 32677bcbb..05ec76f4c 100644 --- a/examples/foundational/49b-thinking-google.py +++ b/examples/foundational/49b-thinking-google.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings, GoogleThinkingConfig from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,20 +56,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), # model="gemini-3-pro-preview", # A more powerful reasoning model, but slower - params=GoogleLLMService.InputParams( - thinking=GoogleLLMService.ThinkingConfig( - # thinking_level="low", # Use this field instead of thinking_budget for Gemini 3 Pro. Defaults to "high". + settings=GoogleLLMSettings( + thinking=GoogleThinkingConfig( thinking_budget=-1, # Dynamic thinking include_thoughts=True, - ) + ), + system_instruction="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.", ), - system_instruction="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() diff --git a/examples/foundational/49c-thinking-functions-anthropic.py b/examples/foundational/49c-thinking-functions-anthropic.py index b070871b1..977b49800 100644 --- a/examples/foundational/49c-thinking-functions-anthropic.py +++ b/examples/foundational/49c-thinking-functions-anthropic.py @@ -23,8 +23,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.anthropic.llm import AnthropicLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.anthropic.llm import ( + AnthropicLLMService, + AnthropicLLMSettings, + AnthropicThinkingConfig, +) +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -77,15 +81,20 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AnthropicLLMService( api_key=os.getenv("ANTHROPIC_API_KEY"), - params=AnthropicLLMService.InputParams( - thinking=AnthropicLLMService.ThinkingConfig(type="enabled", budget_tokens=2048) + settings=AnthropicLLMSettings( + thinking=AnthropicThinkingConfig( + type="enabled", + budget_tokens=2048, + ), + system_instruction="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.", ), - system_instruction="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.", ) llm.register_direct_function(check_flight_status) diff --git a/examples/foundational/49d-thinking-functions-google.py b/examples/foundational/49d-thinking-functions-google.py index 9b5a333de..81b01f744 100644 --- a/examples/foundational/49d-thinking-functions-google.py +++ b/examples/foundational/49d-thinking-functions-google.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings, GoogleThinkingConfig from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -77,20 +77,21 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), # model="gemini-3-pro-preview", # A more powerful reasoning model, but slower - params=GoogleLLMService.InputParams( - thinking=GoogleLLMService.ThinkingConfig( - # thinking_level="low", # Use this field instead of thinking_budget for Gemini 3 Pro. Defaults to "high". + settings=GoogleLLMSettings( + thinking=GoogleThinkingConfig( thinking_budget=-1, # Dynamic thinking include_thoughts=True, - ) + ), + system_instruction="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.", ), - system_instruction="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.", ) llm.register_direct_function(check_flight_status) diff --git a/examples/foundational/52-live-translation.py b/examples/foundational/52-live-translation.py index 6ab0bac18..a90eb3ce4 100644 --- a/examples/foundational/52-live-translation.py +++ b/examples/foundational/52-live-translation.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,12 +59,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady + settings=CartesiaTTSSettings( + voice="d4db5fb9-f44b-4bd1-85fa-192e0f0d75f9", # Spanish-speaking Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a live translation assistant. Your sole purpose is to translate English text into Spanish. When you receive English text from the user, immediately translate it into natural, fluent Spanish. Do not add explanations, commentary, or extra information—only provide the Spanish translation of the text you receive.", + settings=OpenAILLMSettings( + system_instruction="You are a live translation assistant. Your sole purpose is to translate English text into Spanish. When you receive English text from the user, immediately translate it into natural, fluent Spanish. Do not add explanations, commentary, or extra information—only provide the Spanish translation of the text you receive.", + ), ) context = LLMContext() diff --git a/examples/foundational/53-concurrent-llm-evaluation.py b/examples/foundational/53-concurrent-llm-evaluation.py index 9fb44a44f..0ae0afa18 100644 --- a/examples/foundational/53-concurrent-llm-evaluation.py +++ b/examples/foundational/53-concurrent-llm-evaluation.py @@ -24,10 +24,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.audio.vad_processor import VADProcessor from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.groq.llm import GroqLLMService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.groq.llm import GroqLLMService, GroqLLMSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -62,31 +62,28 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - openai_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) - - openai_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.", - }, - ] + openai_llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) groq_llm = GroqLLMService( - api_key=os.getenv("GROQ_API_KEY"), model="meta-llama/llama-4-maverick-17b-128e-instruct" + api_key=os.getenv("GROQ_API_KEY"), + settings=GroqLLMSettings( + model="meta-llama/llama-4-maverick-17b-128e-instruct", + system_instruction="You are a very helpful assistant. Your goal is to demonstrate your capabilities in detail in a creative and helpful way.", + ), ) - groq_messages = [ - { - "role": "system", - "content": "You are a very helpful assistant. Your goal is to demonstrate your capabilities in detail in a creative and helpful way.", - }, - ] - - openai_context = LLMContext(openai_messages) - groq_context = LLMContext(groq_messages) + openai_context = LLMContext() + groq_context = LLMContext() # We use an external VADProcessor because the UserTurnProcessor is shared # across multiple parallel aggregators. The VADProcessor emits @@ -147,11 +144,11 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info(f"Client connected") # Kick off the conversation. - openai_messages.append( - {"role": "system", "content": "Please introduce yourself to the user."} + openai_context.add_message( + {"role": "user", "content": "Please introduce yourself to the user."} ) - groq_messages.append( - {"role": "system", "content": "Please introduce yourself to the user."} + groq_context.add_message( + {"role": "user", "content": "Please introduce yourself to the user."} ) await task.queue_frames([LLMRunFrame()]) diff --git a/examples/foundational/53-concurrent-llm-rtvi-ignored-sources.py b/examples/foundational/53-concurrent-llm-rtvi-ignored-sources.py index b16f8831f..d6b3feac3 100644 --- a/examples/foundational/53-concurrent-llm-rtvi-ignored-sources.py +++ b/examples/foundational/53-concurrent-llm-rtvi-ignored-sources.py @@ -31,9 +31,9 @@ from pipecat.processors.audio.vad_processor import VADProcessor from pipecat.processors.frameworks.rtvi import RTVIObserverParams from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -67,40 +67,31 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) # Main LLM — drives the conversation. Its RTVI events reach the client. - main_llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) - - main_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.", - }, - ] + main_llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction="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.", + ), + ) # Evaluator LLM — silently grades the user's message in the background. # Its RTVI events will be suppressed so the client is unaware of this branch. evaluator_llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), name="EvaluatorLLM", + settings=OpenAILLMSettings( + system_instruction="You are a silent quality evaluator. When given a user message, respond with a single JSON object: {'score': <1-5>, 'reason': ''}. Do not respond conversationally.", + ), ) - evaluator_messages = [ - { - "role": "system", - "content": ( - "You are a silent quality evaluator. When given a user message, " - "respond with a single JSON object: " - '{"score": <1-5>, "reason": ""}. ' - "Do not respond conversationally." - ), - }, - ] - - main_context = LLMContext(main_messages) - evaluator_context = LLMContext(evaluator_messages) + main_context = LLMContext() + evaluator_context = LLMContext() # We use an external VADProcessor because the UserTurnProcessor is shared # across multiple parallel aggregators. The VADProcessor emits @@ -163,10 +154,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): @transport.event_handler("on_client_connected") async def on_client_connected(transport, client): logger.info("Client connected") - main_messages.append( - {"role": "system", "content": "Please introduce yourself to the user."} + main_context.add_message( + {"role": "user", "content": "Please introduce yourself to the user."} + ) + evaluator_context.add_message( + {"role": "user", "content": "Ready to evaluate user messages."} ) - evaluator_messages.append({"role": "system", "content": "Ready to evaluate user messages."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/54-context-summarization-openai.py b/examples/foundational/54-context-summarization-openai.py index 25ea496c3..897ed171f 100644 --- a/examples/foundational/54-context-summarization-openai.py +++ b/examples/foundational/54-context-summarization-openai.py @@ -34,10 +34,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -81,12 +81,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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. You have access to tools to get the current weather - use them when relevant.", + settings=OpenAILLMSettings( + system_instruction="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. You have access to tools to get the current weather - use them when relevant.", + ), ) # Register tool functions diff --git a/examples/foundational/54a-context-summarization-google.py b/examples/foundational/54a-context-summarization-google.py index c79e96c3d..8242ea879 100644 --- a/examples/foundational/54a-context-summarization-google.py +++ b/examples/foundational/54a-context-summarization-google.py @@ -34,9 +34,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google import GoogleLLMService +from pipecat.services.google import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -81,12 +81,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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. You have access to tools to get the current weather - use them when relevant.", + settings=GoogleLLMSettings( + system_instruction="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. You have access to tools to get the current weather - use them when relevant.", + ), ) # Register tool functions diff --git a/examples/foundational/54b-context-summarization-manual-openai.py b/examples/foundational/54b-context-summarization-manual-openai.py index c1ff83ef0..ae1e9bf14 100644 --- a/examples/foundational/54b-context-summarization-manual-openai.py +++ b/examples/foundational/54b-context-summarization-manual-openai.py @@ -34,10 +34,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -78,10 +78,26 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) + system_prompt = """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. + If the user asks you to summarize the conversation, call the + summarize_conversation function. After summarization, briefly acknowledge + that the conversation history has been compressed. + """ + + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction=system_prompt, + ), + ) llm.register_function("summarize_conversation", summarize_conversation) @@ -97,22 +113,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tools = ToolsSchema(standard_tools=[summarize_function]) - 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. " - "If the user asks you to summarize the conversation, call the " - "summarize_conversation function. After summarization, briefly acknowledge " - "that the conversation history has been compressed." - ), - }, - ] - - context = LLMContext(messages, tools=tools) + context = LLMContext(tools=tools) # Automatic summarization is NOT enabled here (enable_auto_context_summarization # defaults to False). The summarizer is still created internally so that @@ -147,7 +148,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info("Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "user", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/54c-context-summarization-dedicated-llm.py b/examples/foundational/54c-context-summarization-dedicated-llm.py index 1dce3890f..c3c4a0c2e 100644 --- a/examples/foundational/54c-context-summarization-dedicated-llm.py +++ b/examples/foundational/54c-context-summarization-dedicated-llm.py @@ -36,11 +36,11 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.google import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.services.llm_service import FunctionCallParams -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -93,16 +93,34 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) + system_prompt = """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. + You have access to tools to get the current weather - use them when relevant. + When you see a block, it contains a compressed summary + of earlier conversation. Use it as reference but don't mention it to the user. + """ + # Primary LLM for conversation (could be any provider) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) + llm = OpenAILLMService( + api_key=os.getenv("OPENAI_API_KEY"), + settings=OpenAILLMSettings( + system_instruction=system_prompt, + ), + ) # Dedicated cheap/fast LLM for summarization only summarization_llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - model="gemini-2.5-flash", + settings=GoogleLLMSettings( + model="gemini-2.5-flash", + ), ) # Register tool functions @@ -126,22 +144,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): ) tools = ToolsSchema(standard_tools=[weather_function]) - 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. Respond to what " - "the user said in a creative and helpful way. You have access to tools to " - "get the current weather - use them when relevant.\n\n" - "When you see a block, it contains a compressed summary " - "of earlier conversation. Use it as reference but don't mention it to the user." - ), - }, - ] - - context = LLMContext(messages, tools=tools) + context = LLMContext(tools=tools) # Create aggregators with custom summarization user_aggregator, assistant_aggregator = LLMContextAggregatorPair( @@ -211,7 +214,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): async def on_client_connected(transport, client): logger.info("Client connected") # Kick off the conversation. - messages.append({"role": "system", "content": "Please introduce yourself to the user."}) + context.add_message({"role": "user", "content": "Please introduce yourself to the user."}) await task.queue_frames([LLMRunFrame()]) @transport.event_handler("on_client_disconnected") diff --git a/examples/foundational/55a-update-settings-deepgram-flux-stt.py b/examples/foundational/55a-update-settings-deepgram-flux-stt.py index ef58fe8fb..cd55f3e37 100644 --- a/examples/foundational/55a-update-settings-deepgram-flux-stt.py +++ b/examples/foundational/55a-update-settings-deepgram-flux-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.flux.stt import DeepgramFluxSTTService, DeepgramFluxSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55a-update-settings-deepgram-sagemaker-stt.py b/examples/foundational/55a-update-settings-deepgram-sagemaker-stt.py index 489ea1276..af080e9db 100644 --- a/examples/foundational/55a-update-settings-deepgram-sagemaker-stt.py +++ b/examples/foundational/55a-update-settings-deepgram-sagemaker-stt.py @@ -23,12 +23,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.sagemaker.stt import ( DeepgramSageMakerSTTService, DeepgramSageMakerSTTSettings, ) -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -62,12 +62,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55a-update-settings-deepgram-stt.py b/examples/foundational/55a-update-settings-deepgram-stt.py index b0521bb19..0519799f0 100644 --- a/examples/foundational/55a-update-settings-deepgram-stt.py +++ b/examples/foundational/55a-update-settings-deepgram-stt.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService, DeepgramSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55b-update-settings-azure-stt.py b/examples/foundational/55b-update-settings-azure-stt.py index 1d3b3fcee..c10f79de4 100644 --- a/examples/foundational/55b-update-settings-azure-stt.py +++ b/examples/foundational/55b-update-settings-azure-stt.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.azure.stt import AzureSTTService, AzureSTTSettings -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -58,12 +58,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55c-update-settings-google-stt.py b/examples/foundational/55c-update-settings-google-stt.py index 2956b8047..9c67a8039 100644 --- a/examples/foundational/55c-update-settings-google-stt.py +++ b/examples/foundational/55c-update-settings-google-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.google.stt import GoogleSTTService, GoogleSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55d-update-settings-assemblyai-stt.py b/examples/foundational/55d-update-settings-assemblyai-stt.py index f8c366a44..1b8ca5eda 100644 --- a/examples/foundational/55d-update-settings-assemblyai-stt.py +++ b/examples/foundational/55d-update-settings-assemblyai-stt.py @@ -22,10 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.assemblyai.models import AssemblyAIConnectionParams from pipecat.services.assemblyai.stt import AssemblyAISTTService, AssemblyAISTTSettings -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -53,19 +52,23 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = AssemblyAISTTService( api_key=os.getenv("ASSEMBLYAI_API_KEY"), - connection_params=AssemblyAIConnectionParams( - speech_model="u3-rt-pro", + settings=AssemblyAISTTSettings( + model="u3-rt-pro", ), ) tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="You are a helpful LLM in a WebRTC call demonstrating dynamic keyterms updates. 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. Try saying difficult names like 'Xiomara', 'Saoirse', or 'Krzystof' to test transcription accuracy.", + settings=OpenAILLMSettings( + system_instruction="You are a helpful LLM in a WebRTC call demonstrating dynamic keyterms updates. 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. Try saying difficult names like 'Xiomara', 'Saoirse', or 'Krzystof' to test transcription accuracy.", + ), ) context = LLMContext() @@ -109,9 +112,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): await task.queue_frame( STTUpdateSettingsFrame( delta=AssemblyAISTTSettings( - connection_params=AssemblyAIConnectionParams( - keyterms_prompt=["Xiomara", "Saoirse", "Krzystof", "Nguyen", "Pipecat"] - ) + keyterms_prompt=["Xiomara", "Saoirse", "Krzystof", "Nguyen", "Pipecat"] ) ) ) diff --git a/examples/foundational/55e-update-settings-gladia-stt.py b/examples/foundational/55e-update-settings-gladia-stt.py index 5b8283f72..24e0dfa6f 100644 --- a/examples/foundational/55e-update-settings-gladia-stt.py +++ b/examples/foundational/55e-update-settings-gladia-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.gladia.stt import GladiaSTTService, GladiaSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55f-update-settings-elevenlabs-realtime-stt.py b/examples/foundational/55f-update-settings-elevenlabs-realtime-stt.py index 8d2c17778..b1f35de13 100644 --- a/examples/foundational/55f-update-settings-elevenlabs-realtime-stt.py +++ b/examples/foundational/55f-update-settings-elevenlabs-realtime-stt.py @@ -22,12 +22,12 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.elevenlabs.stt import ( ElevenLabsRealtimeSTTService, ElevenLabsRealtimeSTTSettings, ) -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -58,12 +58,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55g-update-settings-elevenlabs-stt.py b/examples/foundational/55g-update-settings-elevenlabs-stt.py index 0395f273d..9896a1652 100644 --- a/examples/foundational/55g-update-settings-elevenlabs-stt.py +++ b/examples/foundational/55g-update-settings-elevenlabs-stt.py @@ -23,9 +23,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.elevenlabs.stt import ElevenLabsSTTService, ElevenLabsSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -60,12 +60,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55h-update-settings-speechmatics-stt.py b/examples/foundational/55h-update-settings-speechmatics-stt.py index ba775199a..01f653c7e 100644 --- a/examples/foundational/55h-update-settings-speechmatics-stt.py +++ b/examples/foundational/55h-update-settings-speechmatics-stt.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.speechmatics.stt import SpeechmaticsSTTService, SpeechmaticsSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -53,7 +53,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = SpeechmaticsSTTService( api_key=os.getenv("SPEECHMATICS_API_KEY"), - params=SpeechmaticsSTTService.InputParams( + settings=SpeechmaticsSTTSettings( enable_diarization=True, speaker_active_format="<{speaker_id}>{text}", speaker_passive_format="<{speaker_id}>{text}", @@ -62,12 +62,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55i-update-settings-whisper-api-stt.py b/examples/foundational/55i-update-settings-whisper-api-stt.py index 962a70485..d2c81b0bc 100644 --- a/examples/foundational/55i-update-settings-whisper-api-stt.py +++ b/examples/foundational/55i-update-settings-whisper-api-stt.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.openai.stt import OpenAISTTService from pipecat.services.whisper.base_stt import BaseWhisperSTTSettings from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -61,12 +61,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55j-update-settings-sarvam-stt.py b/examples/foundational/55j-update-settings-sarvam-stt.py index 58f0f80c7..982b22b57 100644 --- a/examples/foundational/55j-update-settings-sarvam-stt.py +++ b/examples/foundational/55j-update-settings-sarvam-stt.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.sarvam.stt import SarvamSTTService, SarvamSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55k-update-settings-soniox-stt.py b/examples/foundational/55k-update-settings-soniox-stt.py index b31a0e708..5fdf0fd82 100644 --- a/examples/foundational/55k-update-settings-soniox-stt.py +++ b/examples/foundational/55k-update-settings-soniox-stt.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.soniox.stt import SonioxSTTService, SonioxSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55l-update-settings-aws-transcribe-stt.py b/examples/foundational/55l-update-settings-aws-transcribe-stt.py index 910bc66b4..07a923616 100644 --- a/examples/foundational/55l-update-settings-aws-transcribe-stt.py +++ b/examples/foundational/55l-update-settings-aws-transcribe-stt.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.aws.stt import AWSTranscribeSTTService, AWSTranscribeSTTSettings -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55m-update-settings-cartesia-stt.py b/examples/foundational/55m-update-settings-cartesia-stt.py index 4956d8d75..e8fc79e94 100644 --- a/examples/foundational/55m-update-settings-cartesia-stt.py +++ b/examples/foundational/55m-update-settings-cartesia-stt.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.stt import CartesiaSTTService, CartesiaSTTSettings -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55n-update-settings-cartesia-http-tts.py b/examples/foundational/55n-update-settings-cartesia-http-tts.py index 0423d855f..9cd935692 100644 --- a/examples/foundational/55n-update-settings-cartesia-http-tts.py +++ b/examples/foundational/55n-update-settings-cartesia-http-tts.py @@ -28,7 +28,7 @@ from pipecat.services.cartesia.tts import ( GenerationConfig, ) from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -58,12 +58,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaHttpTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55n-update-settings-cartesia-tts.py b/examples/foundational/55n-update-settings-cartesia-tts.py index 2ee07b830..37ec2e903 100644 --- a/examples/foundational/55n-update-settings-cartesia-tts.py +++ b/examples/foundational/55n-update-settings-cartesia-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings, GenerationConfig from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,12 +56,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55o-update-settings-elevenlabs-http-tts.py b/examples/foundational/55o-update-settings-elevenlabs-http-tts.py index 7cdf97c25..c8c2af4ab 100644 --- a/examples/foundational/55o-update-settings-elevenlabs-http-tts.py +++ b/examples/foundational/55o-update-settings-elevenlabs-http-tts.py @@ -26,7 +26,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.elevenlabs.tts import ElevenLabsHttpTTSService, ElevenLabsHttpTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -58,13 +58,15 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsHttpTTSService( api_key=os.getenv("ELEVENLABS_API_KEY"), - voice_id=os.getenv("ELEVENLABS_VOICE_ID"), + settings=ElevenLabsHttpTTSSettings(voice=os.getenv("ELEVENLABS_VOICE_ID")), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55o-update-settings-elevenlabs-tts.py b/examples/foundational/55o-update-settings-elevenlabs-tts.py index 6d5d74a17..71ff8c0af 100644 --- a/examples/foundational/55o-update-settings-elevenlabs-tts.py +++ b/examples/foundational/55o-update-settings-elevenlabs-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY"), - voice_id=os.getenv("ELEVENLABS_VOICE_ID"), + settings=ElevenLabsTTSSettings(voice=os.getenv("ELEVENLABS_VOICE_ID")), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55p-update-settings-openai-tts.py b/examples/foundational/55p-update-settings-openai-tts.py index e108f4949..9a1402a1c 100644 --- a/examples/foundational/55p-update-settings-openai-tts.py +++ b/examples/foundational/55p-update-settings-openai-tts.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.openai.tts import OpenAITTSService, OpenAITTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55q-update-settings-deepgram-http-tts.py b/examples/foundational/55q-update-settings-deepgram-http-tts.py index 653e2bd63..dd5220c3f 100644 --- a/examples/foundational/55q-update-settings-deepgram-http-tts.py +++ b/examples/foundational/55q-update-settings-deepgram-http-tts.py @@ -26,7 +26,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.tts import DeepgramHttpTTSService, DeepgramTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -63,7 +63,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55q-update-settings-deepgram-sagemaker-tts.py b/examples/foundational/55q-update-settings-deepgram-sagemaker-tts.py index 6cd396d04..b913375bb 100644 --- a/examples/foundational/55q-update-settings-deepgram-sagemaker-tts.py +++ b/examples/foundational/55q-update-settings-deepgram-sagemaker-tts.py @@ -27,7 +27,7 @@ from pipecat.services.deepgram.sagemaker.tts import ( DeepgramSageMakerTTSSettings, ) from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -63,7 +63,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55q-update-settings-deepgram-tts.py b/examples/foundational/55q-update-settings-deepgram-tts.py index 86d37374a..7164c7b58 100644 --- a/examples/foundational/55q-update-settings-deepgram-tts.py +++ b/examples/foundational/55q-update-settings-deepgram-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.deepgram.tts import DeepgramTTSService, DeepgramTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55r-update-settings-azure-http-tts.py b/examples/foundational/55r-update-settings-azure-http-tts.py index d6b870cc7..148e97f1a 100644 --- a/examples/foundational/55r-update-settings-azure-http-tts.py +++ b/examples/foundational/55r-update-settings-azure-http-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.azure.tts import AzureHttpTTSService, AzureTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,7 +59,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55r-update-settings-azure-tts.py b/examples/foundational/55r-update-settings-azure-tts.py index a564a7267..d23d41a89 100644 --- a/examples/foundational/55r-update-settings-azure-tts.py +++ b/examples/foundational/55r-update-settings-azure-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.azure.tts import AzureTTSService, AzureTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -59,7 +59,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55s-update-settings-google-http-tts.py b/examples/foundational/55s-update-settings-google-http-tts.py index 146d5039e..c573bee6f 100644 --- a/examples/foundational/55s-update-settings-google-http-tts.py +++ b/examples/foundational/55s-update-settings-google-http-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.tts import GoogleHttpTTSService, GoogleHttpTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55s-update-settings-google-stream-tts.py b/examples/foundational/55s-update-settings-google-stream-tts.py index 445ab537b..b13cbd063 100644 --- a/examples/foundational/55s-update-settings-google-stream-tts.py +++ b/examples/foundational/55s-update-settings-google-stream-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.tts import GoogleStreamTTSSettings, GoogleTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55u-update-settings-rime-http-tts.py b/examples/foundational/55u-update-settings-rime-http-tts.py index f57d2b83e..0c00913e7 100644 --- a/examples/foundational/55u-update-settings-rime-http-tts.py +++ b/examples/foundational/55u-update-settings-rime-http-tts.py @@ -25,7 +25,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.rime.tts import RimeHttpTTSService, RimeTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY")) tts = RimeHttpTTSService( - api_key=os.getenv("RIME_API_KEY"), voice_id="eva", aiohttp_session=session + api_key=os.getenv("RIME_API_KEY"), + settings=RimeTTSSettings(voice="eva"), + aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55u-update-settings-rime-tts.py b/examples/foundational/55u-update-settings-rime-tts.py index 5c4cdee67..cb8e09876 100644 --- a/examples/foundational/55u-update-settings-rime-tts.py +++ b/examples/foundational/55u-update-settings-rime-tts.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.rime.tts import RimeTTSService, RimeTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,12 +54,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = RimeTTSService( api_key=os.getenv("RIME_API_KEY"), - voice_id="luna", + settings=RimeTTSSettings(voice="luna"), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55v-update-settings-lmnt-tts.py b/examples/foundational/55v-update-settings-lmnt-tts.py index 0a2c27401..48b0f8d43 100644 --- a/examples/foundational/55v-update-settings-lmnt-tts.py +++ b/examples/foundational/55v-update-settings-lmnt-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.lmnt.tts import LmntTTSService, LmntTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,12 +54,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = LmntTTSService( api_key=os.getenv("LMNT_API_KEY"), - voice_id="lily", + settings=LmntTTSSettings(voice="lily"), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55w-update-settings-fish-tts.py b/examples/foundational/55w-update-settings-fish-tts.py index 87a4a2072..8243f82f2 100644 --- a/examples/foundational/55w-update-settings-fish-tts.py +++ b/examples/foundational/55w-update-settings-fish-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.fish.tts import FishAudioTTSService, FishAudioTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,12 +54,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = FishAudioTTSService( api_key=os.getenv("FISH_API_KEY"), - model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama + settings=FishAudioTTSSettings(voice="4ce7e917cedd4bc2bb2e6ff3a46acaa1"), # Barack Obama ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55x-update-settings-minimax-tts.py b/examples/foundational/55x-update-settings-minimax-tts.py index 66ce52071..fc74bca4c 100644 --- a/examples/foundational/55x-update-settings-minimax-tts.py +++ b/examples/foundational/55x-update-settings-minimax-tts.py @@ -25,7 +25,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.minimax.tts import MiniMaxHttpTTSService, MiniMaxTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -62,7 +62,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55y-update-settings-groq-tts.py b/examples/foundational/55y-update-settings-groq-tts.py index 73e4ac778..632907eaf 100644 --- a/examples/foundational/55y-update-settings-groq-tts.py +++ b/examples/foundational/55y-update-settings-groq-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.groq.tts import GroqTTSService, GroqTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55z-update-settings-hume-tts.py b/examples/foundational/55z-update-settings-hume-tts.py index f16745cad..855610b6b 100644 --- a/examples/foundational/55z-update-settings-hume-tts.py +++ b/examples/foundational/55z-update-settings-hume-tts.py @@ -24,7 +24,7 @@ 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 HumeTTSService, HumeTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,12 +54,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = HumeTTSService( api_key=os.getenv("HUME_API_KEY"), - voice_id="f898a92e-685f-43fa-985b-a46920f0650b", + settings=HumeTTSSettings(voice="f898a92e-685f-43fa-985b-a46920f0650b"), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55za-update-settings-neuphonic-http-tts.py b/examples/foundational/55za-update-settings-neuphonic-http-tts.py index 6c3e510a1..7435b135d 100644 --- a/examples/foundational/55za-update-settings-neuphonic-http-tts.py +++ b/examples/foundational/55za-update-settings-neuphonic-http-tts.py @@ -25,7 +25,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.neuphonic.tts import NeuphonicHttpTTSService, NeuphonicTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -61,7 +61,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55za-update-settings-neuphonic-tts.py b/examples/foundational/55za-update-settings-neuphonic-tts.py index e79ac666f..c0566e86b 100644 --- a/examples/foundational/55za-update-settings-neuphonic-tts.py +++ b/examples/foundational/55za-update-settings-neuphonic-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.neuphonic.tts import NeuphonicTTSService, NeuphonicTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zb-update-settings-inworld-http-tts.py b/examples/foundational/55zb-update-settings-inworld-http-tts.py index ccba1238c..4a2e2a2bc 100644 --- a/examples/foundational/55zb-update-settings-inworld-http-tts.py +++ b/examples/foundational/55zb-update-settings-inworld-http-tts.py @@ -26,7 +26,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.inworld.tts import InworldHttpTTSService, InworldTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -60,7 +60,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zb-update-settings-inworld-tts.py b/examples/foundational/55zb-update-settings-inworld-tts.py index e60e65036..7fcaf67bd 100644 --- a/examples/foundational/55zb-update-settings-inworld-tts.py +++ b/examples/foundational/55zb-update-settings-inworld-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.inworld.tts import InworldTTSService, InworldTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zc-update-settings-gemini-tts.py b/examples/foundational/55zc-update-settings-gemini-tts.py index 637ee65a7..2d2f15cda 100644 --- a/examples/foundational/55zc-update-settings-gemini-tts.py +++ b/examples/foundational/55zc-update-settings-gemini-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.tts import GeminiTTSService, GeminiTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,9 +55,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = GeminiTTSService( credentials=os.getenv("GOOGLE_TEST_CREDENTIALS"), - model="gemini-2.5-flash-tts", - voice_id="Charon", - params=GeminiTTSService.InputParams( + settings=GeminiTTSSettings( + model="gemini-2.5-flash-tts", + voice="Charon", language=Language.EN_US, prompt="You are a helpful AI assistant. Speak in a natural, conversational tone.", ), @@ -65,7 +65,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zd-update-settings-aws-polly-tts.py b/examples/foundational/55zd-update-settings-aws-polly-tts.py index 3b1c1d734..1f6ce56b2 100644 --- a/examples/foundational/55zd-update-settings-aws-polly-tts.py +++ b/examples/foundational/55zd-update-settings-aws-polly-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.aws.tts import AWSPollyTTSService, AWSPollyTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55ze-update-settings-sarvam-http-tts.py b/examples/foundational/55ze-update-settings-sarvam-http-tts.py index ffcf086c6..811ffceb8 100644 --- a/examples/foundational/55ze-update-settings-sarvam-http-tts.py +++ b/examples/foundational/55ze-update-settings-sarvam-http-tts.py @@ -25,7 +25,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.sarvam.tts import SarvamHttpTTSService, SarvamHttpTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -60,7 +60,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55ze-update-settings-sarvam-tts.py b/examples/foundational/55ze-update-settings-sarvam-tts.py index 44301578f..b36e6f81f 100644 --- a/examples/foundational/55ze-update-settings-sarvam-tts.py +++ b/examples/foundational/55ze-update-settings-sarvam-tts.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.sarvam.tts import SarvamTTSService, SarvamTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -56,7 +56,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zf-update-settings-camb-tts.py b/examples/foundational/55zf-update-settings-camb-tts.py index f8058141d..493ad0917 100644 --- a/examples/foundational/55zf-update-settings-camb-tts.py +++ b/examples/foundational/55zf-update-settings-camb-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.camb.tts import CambTTSService, CambTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -57,7 +57,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zh-update-settings-resembleai-tts.py b/examples/foundational/55zh-update-settings-resembleai-tts.py index 7aba67b1f..2c5ef3b25 100644 --- a/examples/foundational/55zh-update-settings-resembleai-tts.py +++ b/examples/foundational/55zh-update-settings-resembleai-tts.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.resembleai.tts import ResembleAITTSService, ResembleAITTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,12 +54,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = ResembleAITTSService( api_key=os.getenv("RESEMBLE_API_KEY"), - voice_id=os.getenv("RESEMBLE_VOICE_UUID"), + settings=ResembleAITTSSettings(voice=os.getenv("RESEMBLE_VOICE_UUID")), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zi-update-settings-azure-llm.py b/examples/foundational/55zi-update-settings-azure-llm.py index b6e8ccf71..5093ba560 100644 --- a/examples/foundational/55zi-update-settings-azure-llm.py +++ b/examples/foundational/55zi-update-settings-azure-llm.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.azure.llm import AzureLLMService -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.azure.llm import AzureLLMService, AzureLLMSettings +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -55,14 +55,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AzureLLMService( api_key=os.getenv("AZURE_CHATGPT_API_KEY"), endpoint=os.getenv("AZURE_CHATGPT_ENDPOINT"), - model=os.getenv("AZURE_CHATGPT_MODEL"), - system_instruction="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.", + settings=AzureLLMSettings( + model=os.getenv("AZURE_CHATGPT_MODEL"), + system_instruction="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() diff --git a/examples/foundational/55zi-update-settings-openai-llm.py b/examples/foundational/55zi-update-settings-openai-llm.py index c9fb026f3..6af897217 100644 --- a/examples/foundational/55zi-update-settings-openai-llm.py +++ b/examples/foundational/55zi-update-settings-openai-llm.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zj-update-settings-anthropic-llm.py b/examples/foundational/55zj-update-settings-anthropic-llm.py index 59ac73da6..8417d0dcd 100644 --- a/examples/foundational/55zj-update-settings-anthropic-llm.py +++ b/examples/foundational/55zj-update-settings-anthropic-llm.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.anthropic.llm import AnthropicLLMService, AnthropicLLMSettings -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,12 +54,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AnthropicLLMService( api_key=os.getenv("ANTHROPIC_API_KEY"), - system_instruction="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.", + settings=AnthropicLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zk-update-settings-google-llm.py b/examples/foundational/55zk-update-settings-google-llm.py index 4a0a3de0f..94b15c886 100644 --- a/examples/foundational/55zk-update-settings-google-llm.py +++ b/examples/foundational/55zk-update-settings-google-llm.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -54,12 +54,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleLLMService( api_key=os.getenv("GOOGLE_API_KEY"), - system_instruction="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.", + settings=GoogleLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zk-update-settings-google-vertex-llm.py b/examples/foundational/55zk-update-settings-google-vertex-llm.py index fe8ef808b..1158c4635 100644 --- a/examples/foundational/55zk-update-settings-google-vertex-llm.py +++ b/examples/foundational/55zk-update-settings-google-vertex-llm.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.llm import GoogleLLMSettings -from pipecat.services.google.llm_vertex import GoogleVertexLLMService +from pipecat.services.google.llm_vertex import GoogleVertexLLMService, GoogleVertexLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,14 +55,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GoogleVertexLLMService( credentials=os.getenv("GOOGLE_VERTEX_TEST_CREDENTIALS"), project_id=os.getenv("GOOGLE_CLOUD_PROJECT_ID"), location=os.getenv("GOOGLE_CLOUD_LOCATION"), - system_instruction="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.", + settings=GoogleVertexLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zp-update-settings-aws-bedrock-llm.py b/examples/foundational/55zp-update-settings-aws-bedrock-llm.py index 72b5ae9be..f4f8f8815 100644 --- a/examples/foundational/55zp-update-settings-aws-bedrock-llm.py +++ b/examples/foundational/55zp-update-settings-aws-bedrock-llm.py @@ -23,7 +23,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.aws.llm import AWSBedrockLLMService, AWSBedrockLLMSettings -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -54,14 +54,18 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = AWSBedrockLLMService( aws_region="us-west-2", - model="us.anthropic.claude-haiku-4-5-20251001-v1:0", - params=AWSBedrockLLMService.InputParams(temperature=0.8), - system_instruction="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.", + settings=AWSBedrockLLMSettings( + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", + temperature=0.8, + system_instruction="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() diff --git a/examples/foundational/55zq-update-settings-fal-stt.py b/examples/foundational/55zq-update-settings-fal-stt.py index 22ee38929..0811523f0 100644 --- a/examples/foundational/55zq-update-settings-fal-stt.py +++ b/examples/foundational/55zq-update-settings-fal-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.fal.stt import FalSTTService, FalSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,12 +54,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zr-update-settings-gradium-stt.py b/examples/foundational/55zr-update-settings-gradium-stt.py index 65c70519d..952f2bb26 100644 --- a/examples/foundational/55zr-update-settings-gradium-stt.py +++ b/examples/foundational/55zr-update-settings-gradium-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.gradium.stt import GradiumSTTService, GradiumSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zt-update-settings-nvidia-segmented-stt.py b/examples/foundational/55zt-update-settings-nvidia-segmented-stt.py index 122619aaa..b46096e0b 100644 --- a/examples/foundational/55zt-update-settings-nvidia-segmented-stt.py +++ b/examples/foundational/55zt-update-settings-nvidia-segmented-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.nvidia.stt import NvidiaSegmentedSTTService, NvidiaSegmentedSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,12 +54,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zt-update-settings-nvidia-stt.py b/examples/foundational/55zt-update-settings-nvidia-stt.py index 232db9bf3..2efa824c3 100644 --- a/examples/foundational/55zt-update-settings-nvidia-stt.py +++ b/examples/foundational/55zt-update-settings-nvidia-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.nvidia.stt import NvidiaSTTService, NvidiaSTTSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zu-update-settings-openai-realtime-stt.py b/examples/foundational/55zu-update-settings-openai-realtime-stt.py index eb7be5c97..9f0e1dc89 100644 --- a/examples/foundational/55zu-update-settings-openai-realtime-stt.py +++ b/examples/foundational/55zu-update-settings-openai-realtime-stt.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.openai.stt import OpenAIRealtimeSTTService, OpenAIRealtimeSTTSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zv-update-settings-asyncai-http-tts.py b/examples/foundational/55zv-update-settings-asyncai-http-tts.py index 79ca4382e..29a774fae 100644 --- a/examples/foundational/55zv-update-settings-asyncai-http-tts.py +++ b/examples/foundational/55zv-update-settings-asyncai-http-tts.py @@ -26,7 +26,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.asyncai.tts import AsyncAIHttpTTSService, AsyncAITTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -59,13 +59,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AsyncAIHttpTTSService( api_key=os.getenv("ASYNCAI_API_KEY", ""), - voice_id=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04"), + settings=AsyncAITTSSettings( + voice=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04") + ), aiohttp_session=session, ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zv-update-settings-asyncai-tts.py b/examples/foundational/55zv-update-settings-asyncai-tts.py index 7e5463d2b..b9c35ebbd 100644 --- a/examples/foundational/55zv-update-settings-asyncai-tts.py +++ b/examples/foundational/55zv-update-settings-asyncai-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.asyncai.tts import AsyncAITTSService, AsyncAITTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = AsyncAITTSService( api_key=os.getenv("ASYNCAI_API_KEY", ""), - voice_id=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04"), + settings=AsyncAITTSSettings( + voice=os.getenv("ASYNCAI_VOICE_ID", "e0f39dc4-f691-4e78-bba5-5c636692cc04") + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zw-update-settings-gradium-tts.py b/examples/foundational/55zw-update-settings-gradium-tts.py index e12d20dd2..52f7c73c5 100644 --- a/examples/foundational/55zw-update-settings-gradium-tts.py +++ b/examples/foundational/55zw-update-settings-gradium-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.gradium.tts import GradiumTTSService, GradiumTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -54,13 +54,15 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = GradiumTTSService( api_key=os.getenv("GRADIUM_API_KEY"), - voice_id="YTpq7expH9539ERJ", + settings=GradiumTTSSettings(voice="YTpq7expH9539ERJ"), url="wss://us.api.gradium.ai/api/speech/tts", ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zx-update-settings-cerebras-llm.py b/examples/foundational/55zx-update-settings-cerebras-llm.py index 3937345e1..c6d27d8e5 100644 --- a/examples/foundational/55zx-update-settings-cerebras-llm.py +++ b/examples/foundational/55zx-update-settings-cerebras-llm.py @@ -22,8 +22,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.cerebras.llm import CerebrasLLMService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.cerebras.llm import CerebrasLLMService, CerebrasLLMSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = CerebrasLLMService( api_key=os.getenv("CEREBRAS_API_KEY"), - system_instruction="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.", + settings=CerebrasLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zy-update-settings-deepseek-llm.py b/examples/foundational/55zy-update-settings-deepseek-llm.py index c96107c40..23e314f8b 100644 --- a/examples/foundational/55zy-update-settings-deepseek-llm.py +++ b/examples/foundational/55zy-update-settings-deepseek-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.deepseek.llm import DeepSeekLLMService +from pipecat.services.deepseek.llm import DeepSeekLLMService, DeepSeekLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = DeepSeekLLMService( api_key=os.getenv("DEEPSEEK_API_KEY"), - system_instruction="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.", + settings=DeepSeekLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zz-update-settings-fireworks-llm.py b/examples/foundational/55zz-update-settings-fireworks-llm.py index 8c4388251..9ea0c9343 100644 --- a/examples/foundational/55zz-update-settings-fireworks-llm.py +++ b/examples/foundational/55zz-update-settings-fireworks-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.fireworks.llm import FireworksLLMService +from pipecat.services.fireworks.llm import FireworksLLMService, FireworksLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,13 +55,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = FireworksLLMService( api_key=os.getenv("FIREWORKS_API_KEY"), - model="accounts/fireworks/models/gpt-oss-20b", - system_instruction="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.", + settings=FireworksLLMSettings( + model="accounts/fireworks/models/gpt-oss-20b", + system_instruction="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() diff --git a/examples/foundational/55zza-update-settings-grok-llm.py b/examples/foundational/55zza-update-settings-grok-llm.py index e75c70b5f..ca537a705 100644 --- a/examples/foundational/55zza-update-settings-grok-llm.py +++ b/examples/foundational/55zza-update-settings-grok-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.grok.llm import GrokLLMService +from pipecat.services.grok.llm import GrokLLMService, GrokLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GrokLLMService( api_key=os.getenv("GROK_API_KEY"), - system_instruction="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.", + settings=GrokLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzb-update-settings-groq-llm.py b/examples/foundational/55zzb-update-settings-groq-llm.py index 2f7f82bb2..3f2ffdb79 100644 --- a/examples/foundational/55zzb-update-settings-groq-llm.py +++ b/examples/foundational/55zzb-update-settings-groq-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.groq.llm import GroqLLMService +from pipecat.services.groq.llm import GroqLLMService, GroqLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,13 +55,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = GroqLLMService( api_key=os.getenv("GROQ_API_KEY"), - model="meta-llama/llama-4-maverick-17b-128e-instruct", - system_instruction="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.", + settings=GroqLLMSettings( + model="meta-llama/llama-4-maverick-17b-128e-instruct", + system_instruction="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() diff --git a/examples/foundational/55zzc-update-settings-mistral-llm.py b/examples/foundational/55zzc-update-settings-mistral-llm.py index ab3bd4f76..b9d591146 100644 --- a/examples/foundational/55zzc-update-settings-mistral-llm.py +++ b/examples/foundational/55zzc-update-settings-mistral-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.mistral.llm import MistralLLMService +from pipecat.services.mistral.llm import MistralLLMService, MistralLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = MistralLLMService( api_key=os.getenv("MISTRAL_API_KEY"), - system_instruction="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.", + settings=MistralLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzd-update-settings-nvidia-llm.py b/examples/foundational/55zzd-update-settings-nvidia-llm.py index a8699c71b..389b51f06 100644 --- a/examples/foundational/55zzd-update-settings-nvidia-llm.py +++ b/examples/foundational/55zzd-update-settings-nvidia-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.nvidia.llm import NvidiaLLMService +from pipecat.services.nvidia.llm import NvidiaLLMService, NvidiaLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,13 +55,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = NvidiaLLMService( api_key=os.getenv("NVIDIA_API_KEY"), - model="meta/llama-3.1-405b-instruct", - system_instruction="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.", + settings=NvidiaLLMSettings( + model="meta/llama-3.1-405b-instruct", + system_instruction="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() diff --git a/examples/foundational/55zze-update-settings-ollama-llm.py b/examples/foundational/55zze-update-settings-ollama-llm.py index 4595604fd..d413267a3 100644 --- a/examples/foundational/55zze-update-settings-ollama-llm.py +++ b/examples/foundational/55zze-update-settings-ollama-llm.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.ollama.llm import OLLamaLLMService +from pipecat.services.ollama.llm import OLLamaLLMService, OllamaLLMSettings from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OLLamaLLMService( - model="llama3.2", - system_instruction="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.", + settings=OllamaLLMSettings( + model="llama3.2", + system_instruction="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.", + ), ) # Update to the model you're running locally context = LLMContext() diff --git a/examples/foundational/55zzf-update-settings-openrouter-llm.py b/examples/foundational/55zzf-update-settings-openrouter-llm.py index 9a381d88b..c34d885f1 100644 --- a/examples/foundational/55zzf-update-settings-openrouter-llm.py +++ b/examples/foundational/55zzf-update-settings-openrouter-llm.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings -from pipecat.services.openrouter.llm import OpenRouterLLMService +from pipecat.services.openrouter.llm import OpenRouterLLMService, OpenRouterLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenRouterLLMService( api_key=os.getenv("OPENROUTER_API_KEY"), - system_instruction="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.", + settings=OpenRouterLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzg-update-settings-perplexity-llm.py b/examples/foundational/55zzg-update-settings-perplexity-llm.py index f55975685..5227c6063 100644 --- a/examples/foundational/55zzg-update-settings-perplexity-llm.py +++ b/examples/foundational/55zzg-update-settings-perplexity-llm.py @@ -22,7 +22,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.perplexity.llm import PerplexityLLMService @@ -55,7 +55,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = PerplexityLLMService(api_key=os.getenv("PERPLEXITY_API_KEY")) diff --git a/examples/foundational/55zzh-update-settings-qwen-llm.py b/examples/foundational/55zzh-update-settings-qwen-llm.py index 019e916cb..584cb23ea 100644 --- a/examples/foundational/55zzh-update-settings-qwen-llm.py +++ b/examples/foundational/55zzh-update-settings-qwen-llm.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings -from pipecat.services.qwen.llm import QwenLLMService +from pipecat.services.qwen.llm import QwenLLMService, QwenLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,13 +55,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = QwenLLMService( api_key=os.getenv("QWEN_API_KEY"), - model="qwen2.5-72b-instruct", - system_instruction="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.", + settings=QwenLLMSettings( + model="qwen2.5-72b-instruct", + system_instruction="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() diff --git a/examples/foundational/55zzi-update-settings-sambanova-llm.py b/examples/foundational/55zzi-update-settings-sambanova-llm.py index 040e95da1..dc246f2cd 100644 --- a/examples/foundational/55zzi-update-settings-sambanova-llm.py +++ b/examples/foundational/55zzi-update-settings-sambanova-llm.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings -from pipecat.services.sambanova.llm import SambaNovaLLMService +from pipecat.services.sambanova.llm import SambaNovaLLMService, SambaNovaLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,12 +55,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = SambaNovaLLMService( api_key=os.getenv("SAMBANOVA_API_KEY"), - system_instruction="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.", + settings=SambaNovaLLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzj-update-settings-together-llm.py b/examples/foundational/55zzj-update-settings-together-llm.py index b1c8c049d..bd855bcff 100644 --- a/examples/foundational/55zzj-update-settings-together-llm.py +++ b/examples/foundational/55zzj-update-settings-together-llm.py @@ -22,10 +22,10 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.base_llm import OpenAILLMSettings -from pipecat.services.together.llm import TogetherLLMService +from pipecat.services.together.llm import TogetherLLMService, TogetherLLMSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams @@ -55,13 +55,17 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = TogetherLLMService( api_key=os.getenv("TOGETHER_API_KEY"), - model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", - system_instruction="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.", + settings=TogetherLLMSettings( + model="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", + system_instruction="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() diff --git a/examples/foundational/55zzl-update-settings-nvidia-tts.py b/examples/foundational/55zzl-update-settings-nvidia-tts.py index 5bc89bd58..e667a9ca3 100644 --- a/examples/foundational/55zzl-update-settings-nvidia-tts.py +++ b/examples/foundational/55zzl-update-settings-nvidia-tts.py @@ -24,7 +24,7 @@ from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.nvidia.tts import NvidiaTTSService, NvidiaTTSSettings -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.transcriptions.language import Language from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -57,7 +57,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzm-update-settings-speechmatics-tts.py b/examples/foundational/55zzm-update-settings-speechmatics-tts.py index d9eaaec86..2e8bb46a6 100644 --- a/examples/foundational/55zzm-update-settings-speechmatics-tts.py +++ b/examples/foundational/55zzm-update-settings-speechmatics-tts.py @@ -24,7 +24,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.speechmatics.tts import SpeechmaticsTTSService, SpeechmaticsTTSSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -61,7 +61,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/55zzn-update-settings-groq-stt.py b/examples/foundational/55zzn-update-settings-groq-stt.py index 1d488119c..d6dac9e1f 100644 --- a/examples/foundational/55zzn-update-settings-groq-stt.py +++ b/examples/foundational/55zzn-update-settings-groq-stt.py @@ -22,9 +22,9 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.groq.stt import GroqSTTService -from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.openai.llm import OpenAILLMService, OpenAILLMSettings from pipecat.services.whisper.base_stt import BaseWhisperSTTSettings from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.daily.transport import DailyParams @@ -57,12 +57,16 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService( api_key=os.getenv("OPENAI_API_KEY"), - system_instruction="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.", + settings=OpenAILLMSettings( + system_instruction="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() diff --git a/examples/foundational/56-lemonslice-transport.py b/examples/foundational/56-lemonslice-transport.py index a3b6b60d3..8dc400841 100644 --- a/examples/foundational/56-lemonslice-transport.py +++ b/examples/foundational/56-lemonslice-transport.py @@ -23,8 +23,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( LLMUserAggregatorParams, ) from pipecat.services.deepgram.stt import DeepgramSTTService -from pipecat.services.elevenlabs.tts import ElevenLabsTTSService -from pipecat.services.groq.llm import GroqLLMService +from pipecat.services.elevenlabs.tts import ElevenLabsTTSService, ElevenLabsTTSSettings +from pipecat.services.groq.llm import GroqLLMService, GroqLLMSettings from pipecat.transports.lemonslice.transport import ( LemonSliceNewSessionRequest, LemonSliceParams, @@ -57,12 +57,16 @@ async def main(): llm = GroqLLMService( api_key=os.getenv("GROQ_API_KEY"), - system_instruction="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.", + settings=GroqLLMSettings( + system_instruction="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.", + ), ) tts = ElevenLabsTTSService( api_key=os.getenv("ELEVENLABS_API_KEY", ""), - voice_id=os.getenv("ELEVENLABS_VOICE_ID", ""), + settings=ElevenLabsTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) context = LLMContext() diff --git a/examples/quickstart/bot.py b/examples/quickstart/bot.py index fbe27d783..956331d50 100644 --- a/examples/quickstart/bot.py +++ b/examples/quickstart/bot.py @@ -45,7 +45,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( ) from pipecat.runner.types import RunnerArguments from pipecat.runner.utils import create_transport -from pipecat.services.cartesia.tts import CartesiaTTSService +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.base_transport import BaseTransport, TransportParams @@ -63,7 +63,9 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + settings=CartesiaTTSSettings( + voice="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady + ), ) llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) diff --git a/scripts/evals/eval.py b/scripts/evals/eval.py index 8084bc3a1..c2316e123 100644 --- a/scripts/evals/eval.py +++ b/scripts/evals/eval.py @@ -48,8 +48,8 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor from pipecat.processors.frame_processor import FrameDirection from pipecat.runner.types import RunnerArguments -from pipecat.services.cartesia.tts import CartesiaTTSService -from pipecat.services.deepgram.stt import DeepgramSTTService, LiveOptions +from pipecat.services.cartesia.tts import CartesiaTTSService, CartesiaTTSSettings +from pipecat.services.deepgram.stt import DeepgramSTTService, DeepgramSTTSettings from pipecat.services.llm_service import FunctionCallParams from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.daily.transport import DailyParams, DailyTransport @@ -243,7 +243,7 @@ async def run_eval_pipeline( # 5" (in audio) this can be converted to "32 is 5". stt = DeepgramSTTService( api_key=os.getenv("DEEPGRAM_API_KEY"), - live_options=LiveOptions( + settings=DeepgramSTTSettings( language="multi", smart_format=False, ), @@ -251,10 +251,32 @@ async def run_eval_pipeline( tts = CartesiaTTSService( api_key=os.getenv("CARTESIA_API_KEY"), - voice_id="97f4b8fb-f2fe-444b-bb9a-c109783a857a", # Nathan + settings=CartesiaTTSSettings( + voice="97f4b8fb-f2fe-444b-bb9a-c109783a857a", # Nathan + ), ) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY")) + # Load example prompt depending on image. + example_prompt = "" + example_image: Optional[ImageFile] = None + if isinstance(eval_config.prompt, str): + example_prompt = eval_config.prompt + elif isinstance(eval_config.prompt, tuple): + example_prompt, example_image = eval_config.prompt + + common_system_prompt = ( + "You should only call the eval function if:\n" + "- The user explicitly attempts to answer the question, AND\n" + f"- Their answer can be cleanly evaluated using: {eval_config.eval}\n" + "Ignore greetings, comments, non-answers, or requests for clarification.\n" + "Numerical word answers are allowed (e.g., 'five' is the same as '5').\n" + ) + if eval_config.eval_speaks_first: + system_prompt = f"You are an evaluation agent, be extremly brief. You will start the conversation by saying: '{example_prompt}'. {common_system_prompt}" + else: + system_prompt = f"You are an evaluation agent, be extremly brief. First, ask one question: {example_prompt}. {common_system_prompt}" + + llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), system_instruction=system_prompt) llm.register_function("eval_function", eval_runner.function_assert_eval) @@ -281,34 +303,7 @@ async def run_eval_pipeline( ) tools = ToolsSchema(standard_tools=[eval_function]) - # Load example prompt depending on image. - example_prompt = "" - example_image: Optional[ImageFile] = None - if isinstance(eval_config.prompt, str): - example_prompt = eval_config.prompt - elif isinstance(eval_config.prompt, tuple): - example_prompt, example_image = eval_config.prompt - - common_system_prompt = ( - "You should only call the eval function if:\n" - "- The user explicitly attempts to answer the question, AND\n" - f"- Their answer can be cleanly evaluated using: {eval_config.eval}\n" - "Ignore greetings, comments, non-answers, or requests for clarification.\n" - "Numerical word answers are allowed (e.g., 'five' is the same as '5').\n" - ) - if eval_config.eval_speaks_first: - system_prompt = f"You are an evaluation agent, be extremly brief. You will start the conversation by saying: '{example_prompt}'. {common_system_prompt}" - else: - system_prompt = f"You are an evaluation agent, be extremly brief. First, ask one question: {example_prompt}. {common_system_prompt}" - - messages = [ - { - "role": "system", - "content": system_prompt, - }, - ] - - context = LLMContext(messages, tools) + context = LLMContext(tools=tools) context_aggregator = LLMContextAggregatorPair( context, user_params=LLMUserAggregatorParams( diff --git a/src/pipecat/services/anthropic/llm.py b/src/pipecat/services/anthropic/llm.py index 5981d3e50..369c2a4ed 100644 --- a/src/pipecat/services/anthropic/llm.py +++ b/src/pipecat/services/anthropic/llm.py @@ -58,7 +58,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService from pipecat.services.settings import NOT_GIVEN as _NOT_GIVEN -from pipecat.services.settings import LLMSettings, _NotGiven, is_given +from pipecat.services.settings import LLMSettings, _NotGiven, _warn_deprecated_param, is_given from pipecat.utils.tracing.service_decorators import traced_llm try: @@ -170,6 +170,10 @@ class AnthropicLLMService(LLMService): class InputParams(BaseModel): """Input parameters for Anthropic model inference. + .. deprecated:: + Use ``AnthropicLLMSettings`` instead. Pass settings directly via the + ``settings`` parameter of :class:`AnthropicLLMService`. + Parameters: enable_prompt_caching: Whether to enable the prompt caching feature. enable_prompt_caching_beta (deprecated): Whether to enable the beta prompt caching feature. @@ -213,62 +217,99 @@ class AnthropicLLMService(LLMService): self, *, api_key: str, - model: str = "claude-sonnet-4-6", + model: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[AnthropicLLMSettings] = None, client=None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, - system_instruction: Optional[str] = None, **kwargs, ): """Initialize the Anthropic LLM service. Args: api_key: Anthropic API key for authentication. - model: Model name to use. Defaults to "claude-sonnet-4-6". + model: Model name to use. + + .. deprecated:: + Use ``settings=AnthropicLLMSettings(model=...)`` instead. + params: Optional model parameters for inference. + + .. deprecated:: + Use ``settings=AnthropicLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. client: Optional custom Anthropic client instance. retry_timeout_secs: Request timeout in seconds for retry logic. retry_on_timeout: Whether to retry the request once if it times out. - system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - params = params or AnthropicLLMService.InputParams() - - super().__init__( - settings=AnthropicLLMSettings( - model=model, - max_tokens=params.max_tokens, - enable_prompt_caching=( - params.enable_prompt_caching - if params.enable_prompt_caching is not None - else ( - params.enable_prompt_caching_beta - if params.enable_prompt_caching_beta is not None - else False - ) - ), - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - thinking=params.thinking, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), - **kwargs, + # 1. Initialize default_settings with hardcoded defaults + default_settings = AnthropicLLMSettings( + model="claude-sonnet-4-6", + system_instruction=None, + max_tokens=4096, + enable_prompt_caching=False, + temperature=NOT_GIVEN, + top_k=NOT_GIVEN, + top_p=NOT_GIVEN, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + thinking=NOT_GIVEN, + extra={}, ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", AnthropicLLMSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AnthropicLLMSettings) + if not settings: + default_settings.max_tokens = params.max_tokens + default_settings.temperature = params.temperature + default_settings.top_k = params.top_k + default_settings.top_p = params.top_p + default_settings.thinking = params.thinking + if isinstance(params.extra, dict): + default_settings.extra = params.extra + # Handle enable_prompt_caching / enable_prompt_caching_beta + enable_prompt_caching = params.enable_prompt_caching + if params.enable_prompt_caching_beta is not None: + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn( + "enable_prompt_caching_beta is deprecated. " + "Use enable_prompt_caching instead.", + DeprecationWarning, + stacklevel=2, + ) + if enable_prompt_caching is None: + enable_prompt_caching = params.enable_prompt_caching_beta + default_settings.enable_prompt_caching = enable_prompt_caching or False + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._client = client or AsyncAnthropic( api_key=api_key ) # if the client is provided, use it and remove it, otherwise create a new one self._retry_timeout_secs = retry_timeout_secs self._retry_on_timeout = retry_on_timeout - self._system_instruction = system_instruction - if self._system_instruction: - logger.debug(f"{self}: Using system instruction: {self._system_instruction}") + if self._settings.system_instruction: + logger.debug(f"{self}: Using system instruction: {self._settings.system_instruction}") def can_generate_metrics(self) -> bool: """Check if this service can generate usage metrics. @@ -402,13 +443,13 @@ class AnthropicLLMService(LLMService): params: AnthropicLLMInvocationParams = adapter.get_llm_invocation_params( context, enable_prompt_caching=self._settings.enable_prompt_caching ) - if self._system_instruction: + if self._settings.system_instruction: if params["system"] is not NOT_GIVEN: logger.warning( f"{self}: Both system_instruction and a system message in context are" " set. Using system_instruction." ) - params["system"] = self._system_instruction + params["system"] = self._settings.system_instruction return params # Anthropic-specific context diff --git a/src/pipecat/services/assemblyai/models.py b/src/pipecat/services/assemblyai/models.py index 2c6b3a1dc..efc13d482 100644 --- a/src/pipecat/services/assemblyai/models.py +++ b/src/pipecat/services/assemblyai/models.py @@ -124,6 +124,9 @@ AnyMessage = BeginMessage | TurnMessage | SpeechStartedMessage | TerminationMess class AssemblyAIConnectionParams(BaseModel): """Configuration parameters for AssemblyAI WebSocket connection. + .. deprecated:: 0.0.105 + Use ``settings=AssemblyAISTTSettings(foo=...)`` instead. + Parameters: sample_rate: Audio sample rate in Hz. Defaults to 16000. encoding: Audio encoding format. Defaults to "pcm_s16le". diff --git a/src/pipecat/services/assemblyai/stt.py b/src/pipecat/services/assemblyai/stt.py index c62ae959b..ec4130ea5 100644 --- a/src/pipecat/services/assemblyai/stt.py +++ b/src/pipecat/services/assemblyai/stt.py @@ -13,7 +13,7 @@ WebSocket API for streaming audio transcription. import asyncio import json from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, Dict, Optional +from typing import Any, AsyncGenerator, Dict, List, Optional from urllib.parse import urlencode from loguru import logger @@ -32,7 +32,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import ASSEMBLYAI_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language @@ -83,15 +83,38 @@ def map_language_from_assemblyai(language_code: str) -> Language: class AssemblyAISTTSettings(STTSettings): """Settings for the AssemblyAI STT service. - See :class:`AssemblyAIConnectionParams` for detailed parameter descriptions. - Parameters: - connection_params: Connection configuration parameters. + formatted_finals: Whether to enable transcript formatting. + word_finalization_max_wait_time: Maximum time to wait for word + finalization in milliseconds. + end_of_turn_confidence_threshold: Confidence threshold for + end-of-turn detection. + min_turn_silence: Minimum silence duration when confident about + end-of-turn. + max_turn_silence: Maximum silence duration before forcing + end-of-turn. + keyterms_prompt: List of key terms to guide transcription. + prompt: Optional text prompt to guide the transcription. Only + used when model is "u3-rt-pro". + language_detection: Enable automatic language detection. + format_turns: Whether to format transcript turns. + speaker_labels: Enable speaker diarization. """ - connection_params: AssemblyAIConnectionParams | _NotGiven = field( + formatted_finals: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + word_finalization_max_wait_time: int | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) + end_of_turn_confidence_threshold: float | None | _NotGiven = field( + default_factory=lambda: NOT_GIVEN + ) + min_turn_silence: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + max_turn_silence: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + keyterms_prompt: List[str] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + language_detection: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + format_turns: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + speaker_labels: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class AssemblyAISTTService(WebsocketSTTService): @@ -108,12 +131,15 @@ class AssemblyAISTTService(WebsocketSTTService): self, *, api_key: str, - language: Language = Language.EN, # AssemblyAI only supports English + language: Optional[Language] = None, api_endpoint_base_url: str = "wss://streaming.assemblyai.com/v3/ws", - connection_params: AssemblyAIConnectionParams = AssemblyAIConnectionParams(), + sample_rate: int = 16000, + encoding: str = "pcm_s16le", + connection_params: Optional[AssemblyAIConnectionParams] = None, vad_force_turn_endpoint: bool = True, should_interrupt: bool = True, speaker_format: Optional[str] = None, + settings: Optional[AssemblyAISTTSettings] = None, ttfs_p99_latency: Optional[float] = ASSEMBLYAI_TTFS_P99, **kwargs, ): @@ -122,8 +148,18 @@ class AssemblyAISTTService(WebsocketSTTService): Args: api_key: AssemblyAI API key for authentication. language: Language code for transcription. Defaults to English (Language.EN). + + .. deprecated:: 0.0.105 + Use ``settings=AssemblyAISTTSettings(language=...)`` instead. + api_endpoint_base_url: WebSocket endpoint URL. Defaults to AssemblyAI's streaming endpoint. - connection_params: Connection configuration parameters. Defaults to AssemblyAIConnectionParams(). + sample_rate: Audio sample rate in Hz. Defaults to 16000. + encoding: Audio encoding format. Defaults to "pcm_s16le". + connection_params: Connection configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=AssemblyAISTTSettings(...)`` instead. + vad_force_turn_endpoint: Controls turn detection mode. When True (Pipecat mode, default): Forces AssemblyAI to return finals ASAP so Pipecat's turn detection (e.g., Smart Turn) decides when the user is done. @@ -134,7 +170,6 @@ class AssemblyAISTTService(WebsocketSTTService): When False (AssemblyAI turn detection mode, u3-rt-pro only): AssemblyAI's model controls turn endings using built-in turn detection. - Uses AssemblyAI API defaults for all parameters (unless user explicitly sets them) - - Respects all user-provided connection_params as-is - Emits UserStarted/StoppedSpeakingFrame from STT - No ForceEndpoint on VAD stop should_interrupt: Whether to interrupt the bot when the user starts speaking @@ -144,34 +179,80 @@ class AssemblyAISTTService(WebsocketSTTService): Use {speaker} for speaker label and {text} for transcript text. Example: "<{speaker}>{text}" or "{speaker}: {text}" If None, transcript text is not modified. Defaults to None. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. """ - # AssemblyAI turn detection mode (vad_force_turn_endpoint=False) requires the - # SpeechStarted event for reliable barge-in. Only u3-rt-pro supports - # this. Other models must use Pipecat turn detection. - is_u3_pro = connection_params.speech_model == "u3-rt-pro" + # 1. Initialize default_settings with hardcoded defaults + default_settings = AssemblyAISTTSettings( + model="u3-rt-pro", + language=Language.EN, + formatted_finals=True, + word_finalization_max_wait_time=None, + end_of_turn_confidence_threshold=None, + min_turn_silence=None, + max_turn_silence=None, + keyterms_prompt=None, + prompt=None, + language_detection=None, + format_turns=True, + speaker_labels=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if language is not None: + _warn_deprecated_param("language", AssemblyAISTTSettings, "language") + default_settings.language = language + + # 3. Apply connection_params overrides (deprecated) — only if settings not provided + if connection_params is not None: + _warn_deprecated_param("connection_params", AssemblyAISTTSettings) + if not settings: + sample_rate = connection_params.sample_rate + encoding = connection_params.encoding + default_settings.model = connection_params.speech_model + default_settings.formatted_finals = connection_params.formatted_finals + default_settings.word_finalization_max_wait_time = ( + connection_params.word_finalization_max_wait_time + ) + default_settings.end_of_turn_confidence_threshold = ( + connection_params.end_of_turn_confidence_threshold + ) + default_settings.min_turn_silence = connection_params.min_turn_silence + default_settings.max_turn_silence = connection_params.max_turn_silence + default_settings.keyterms_prompt = connection_params.keyterms_prompt + default_settings.prompt = connection_params.prompt + default_settings.language_detection = connection_params.language_detection + default_settings.format_turns = connection_params.format_turns + default_settings.speaker_labels = connection_params.speaker_labels + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + # 5. Validate final settings + is_u3_pro = default_settings.model == "u3-rt-pro" if not vad_force_turn_endpoint and not is_u3_pro: raise ValueError( f"AssemblyAI turn detection mode (vad_force_turn_endpoint=False) requires " f"u3-rt-pro for SpeechStarted support. Either set " - f"vad_force_turn_endpoint=True for {connection_params.speech_model}, " - f"or use speech_model='u3-rt-pro'." + f"vad_force_turn_endpoint=True for {default_settings.model}, " + f"or use model='u3-rt-pro'." ) - # Validate that prompt and keyterms_prompt are not both set - if connection_params.prompt is not None and connection_params.keyterms_prompt is not None: + if default_settings.prompt is not None and default_settings.keyterms_prompt is not None: raise ValueError( "The prompt and keyterms_prompt parameters cannot be used in the same request. " "Please choose either one or the other based on your use case. When you use " "keyterms_prompt, your boosted words are appended to the default prompt automatically. " - "Or to boost within prompt: + Make sure to boost the words in the audio. " + "Or to boost within prompt: + Make sure to boost the words " + "in the audio. " "For more info go to: https://www.assemblyai.com/docs/streaming/universal-3-pro" ) - # Warn if user sets a custom prompt (recommend testing without one first) - if connection_params.prompt is not None: + if default_settings.prompt is not None: logger.warning( "Custom prompt detected. Prompting is a beta feature. We recommend testing " "with no prompt first, as this will use our optimized default prompt for " @@ -180,19 +261,14 @@ class AssemblyAISTTService(WebsocketSTTService): "https://www.assemblyai.com/docs/streaming/prompting" ) - # When vad_force_turn_endpoint is enabled, configure connection params - # for Pipecat turn detection mode (fast finals for smart turn analyzer) + # 6. Configure pipecat turn mode (mutates default_settings) if vad_force_turn_endpoint: - connection_params = self._configure_pipecat_turn_mode(connection_params, is_u3_pro) + self._configure_pipecat_turn_mode(default_settings, is_u3_pro) super().__init__( - sample_rate=connection_params.sample_rate, + sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=AssemblyAISTTSettings( - model=None, - language=language, - connection_params=connection_params, - ), + settings=default_settings, **kwargs, ) @@ -202,6 +278,9 @@ class AssemblyAISTTService(WebsocketSTTService): self._should_interrupt = should_interrupt self._speaker_format = speaker_format + # Init-only audio config (not runtime-updatable) + self._encoding = encoding + self._termination_event = asyncio.Event() self._received_termination = False self._connected = False @@ -214,10 +293,8 @@ class AssemblyAISTTService(WebsocketSTTService): self._user_speaking = False - def _configure_pipecat_turn_mode( - self, connection_params: AssemblyAIConnectionParams, is_u3_pro: bool - ) -> AssemblyAIConnectionParams: - """Configure connection params for Pipecat turn detection mode. + def _configure_pipecat_turn_mode(self, settings: AssemblyAISTTSettings, is_u3_pro: bool): + """Configure settings for Pipecat turn detection mode. When vad_force_turn_endpoint is enabled, force AssemblyAI to return finals as fast as possible so Pipecat's smart turn analyzer can decide @@ -236,46 +313,31 @@ class AssemblyAISTTService(WebsocketSTTService): - max_turn_silence: not set (API default) Args: - connection_params: The user-provided connection parameters. + settings: The settings to configure in place. is_u3_pro: Whether using u3-rt-pro model. - - Returns: - Updated connection parameters configured for Pipecat turn mode. """ - updates = {} - if is_u3_pro: # u3-rt-pro: Synchronize max_turn_silence with min_turn_silence - min_silence = connection_params.min_turn_silence + min_silence = settings.min_turn_silence if min_silence is None: min_silence = 100 # Warn if user set max_turn_silence (will be overridden) - if connection_params.max_turn_silence is not None: + if settings.max_turn_silence is not None: logger.warning( - f"Your max_turn_silence value ({connection_params.max_turn_silence}ms) will be " + f"Your max_turn_silence value ({settings.max_turn_silence}ms) will be " f"OVERRIDDEN in Pipecat mode (vad_force_turn_endpoint=True). It will be set to " f"{min_silence}ms (matching min_turn_silence) and SENT to " f"AssemblyAI to avoid double turn detection. To use your max_turn_silence as-is, " f"switch to AssemblyAI turn detection mode (vad_force_turn_endpoint=False)." ) - updates = { - "min_turn_silence": min_silence, - "max_turn_silence": min_silence, - } + settings.min_turn_silence = min_silence + settings.max_turn_silence = min_silence else: # universal-streaming: Different configuration (works differently) - updates = { - "end_of_turn_confidence_threshold": 1.0, - "min_turn_silence": 160, - } - - # Apply updates if any - if updates: - connection_params = connection_params.model_copy(update=updates) - - return connection_params + settings.end_of_turn_confidence_threshold = 1.0 + settings.min_turn_silence = 160 def can_generate_metrics(self) -> bool: """Check if the service can generate metrics. @@ -285,18 +347,11 @@ class AssemblyAISTTService(WebsocketSTTService): """ return True - async def _update_settings(self, delta: STTSettings) -> dict[str, Any]: - """Apply a settings delta and send UpdateConfiguration if connected. - - Stores settings changes and sends UpdateConfiguration message to AssemblyAI - without reconnecting. Supports updating: - - keyterms_prompt: List of terms to boost (can be empty array to clear) - - prompt: Custom prompt text (u3-rt-pro only) - - max_turn_silence: Maximum silence before forcing turn end - - min_turn_silence: Silence before EOT check + async def _update_settings(self, delta: AssemblyAISTTSettings) -> dict[str, Any]: + """Apply a settings delta and reconnect to apply changes. Args: - delta: A :class:`STTSettings` (or ``AssemblyAISTTSettings``) delta. + delta: A settings delta with updated values. Returns: Dict mapping changed field names to their previous values. @@ -306,72 +361,9 @@ class AssemblyAISTTService(WebsocketSTTService): if not changed: return changed - # If websocket is connected, send UpdateConfiguration for supported params - if ( - self._websocket - and self._websocket.state is State.OPEN - and "connection_params" in changed - ): - # Build UpdateConfiguration message - update_config = {"type": "UpdateConfiguration"} - conn_params = self._settings.connection_params - - # Get the old connection_params to see what changed - old_conn_params = changed.get("connection_params") - - # Check each potentially changed parameter - if ( - old_conn_params is None - or conn_params.keyterms_prompt != old_conn_params.keyterms_prompt - ): - if conn_params.keyterms_prompt is not None: - update_config["keyterms_prompt"] = conn_params.keyterms_prompt - logger.info(f"Updating keyterms_prompt to: {conn_params.keyterms_prompt}") - - if old_conn_params is None or conn_params.prompt != old_conn_params.prompt: - if conn_params.prompt is not None: - if conn_params.speech_model != "u3-rt-pro": - logger.warning( - f"prompt parameter is only supported with u3-rt-pro model, " - f"current model is {conn_params.speech_model}" - ) - else: - update_config["prompt"] = conn_params.prompt - logger.info(f"Updating prompt") - - if ( - old_conn_params is None - or conn_params.max_turn_silence != old_conn_params.max_turn_silence - ): - if conn_params.max_turn_silence is not None: - update_config["max_turn_silence"] = conn_params.max_turn_silence - logger.info(f"Updating max_turn_silence to: {conn_params.max_turn_silence}ms") - - if ( - old_conn_params is None - or conn_params.min_turn_silence != old_conn_params.min_turn_silence - ): - if conn_params.min_turn_silence is not None: - update_config["min_turn_silence"] = conn_params.min_turn_silence - logger.info(f"Updating min_turn_silence to: {conn_params.min_turn_silence}ms") - - # Send update if we have parameters to update - if len(update_config) > 1: # More than just "type" - try: - await self._websocket.send(json.dumps(update_config)) - logger.info(f"Sent UpdateConfiguration: {update_config}") - except Exception as e: - logger.error(f"Failed to send UpdateConfiguration: {e}") - elif "connection_params" in changed: - logger.warning( - "Connection params changed but WebSocket not connected. " - "Settings will be applied on next connection." - ) - - # Warn about other settings that can't be changed dynamically - other_changes = {k: v for k, v in changed.items() if k not in ["connection_params"]} - if other_changes: - self._warn_unhandled_updated_settings(other_changes) + # Reconnect to apply updated settings (they become WS query params) + await self._disconnect() + await self._connect() return changed @@ -449,19 +441,41 @@ class AssemblyAISTTService(WebsocketSTTService): def _build_ws_url(self) -> str: """Build WebSocket URL with query parameters using urllib.parse.urlencode.""" - params = {} - for k, v in self._settings.connection_params.model_dump().items(): - # Skip deprecated parameter - it's been migrated to min_turn_silence - if k == "min_end_of_turn_silence_when_confident": - continue + s = self._settings + params: dict[str, Any] = {} + + # Init-only audio config + params["sample_rate"] = self.sample_rate + params["encoding"] = self._encoding + + # Map model → speech_model (AssemblyAI API naming) + if s.model is not None: + params["speech_model"] = s.model + + # Settings fields (skip None values) + optional_fields = { + "formatted_finals": s.formatted_finals, + "word_finalization_max_wait_time": s.word_finalization_max_wait_time, + "end_of_turn_confidence_threshold": s.end_of_turn_confidence_threshold, + "min_turn_silence": s.min_turn_silence, + "max_turn_silence": s.max_turn_silence, + "prompt": s.prompt, + "language_detection": s.language_detection, + "format_turns": s.format_turns, + "speaker_labels": s.speaker_labels, + } + + for k, v in optional_fields.items(): if v is not None: - if k == "keyterms_prompt": - params[k] = json.dumps(v) - elif isinstance(v, bool): + if isinstance(v, bool): params[k] = str(v).lower() else: params[k] = v + # Special handling for keyterms_prompt (needs JSON encoding) + if s.keyterms_prompt is not None: + params["keyterms_prompt"] = json.dumps(s.keyterms_prompt) + if params: query_string = urlencode(params) return f"{self._api_endpoint_base_url}?{query_string}" @@ -693,7 +707,7 @@ class AssemblyAISTTService(WebsocketSTTService): # Determine if this is a final turn from AssemblyAI is_final_turn = message.end_of_turn and ( - not self._settings.connection_params.format_turns or message.turn_is_formatted + not self._settings.format_turns or message.turn_is_formatted ) if self._vad_force_turn_endpoint: diff --git a/src/pipecat/services/asyncai/tts.py b/src/pipecat/services/asyncai/tts.py index 4f1fd5a58..3b1296752 100644 --- a/src/pipecat/services/asyncai/tts.py +++ b/src/pipecat/services/asyncai/tts.py @@ -9,8 +9,8 @@ import asyncio import base64 import json -from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, Mapping, Optional +from dataclasses import dataclass +from typing import Any, AsyncGenerator, Optional import aiohttp from loguru import logger @@ -27,7 +27,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -75,28 +75,9 @@ def language_to_async_language(language: Language) -> Optional[str]: @dataclass class AsyncAITTSSettings(TTSSettings): - """Settings for Async AI TTS services. + """Settings for Async AI TTS services.""" - Parameters: - output_container: Audio container format (e.g. "raw"). - output_encoding: Audio encoding format (e.g. "pcm_s16le"). - output_sample_rate: Audio sample rate in Hz. - """ - - output_container: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - - @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "AsyncAITTSSettings": - """Construct settings from a plain dict, destructuring legacy nested ``output_format``.""" - flat = dict(settings) - nested = flat.pop("output_format", None) - if isinstance(nested, dict): - flat.setdefault("output_container", nested.get("container")) - flat.setdefault("output_encoding", nested.get("encoding")) - flat.setdefault("output_sample_rate", nested.get("sample_rate")) - return super().from_mapping(flat) + pass class AsyncAITTSService(AudioContextTTSService): @@ -110,6 +91,9 @@ class AsyncAITTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for Async TTS configuration. + .. deprecated:: 0.0.105 + Use ``AsyncAITTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -120,14 +104,15 @@ class AsyncAITTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, version: str = "v1", url: str = "wss://api.async.com/text_to_speech/websocket/ws", - model: str = "async_flash_v1.0", + model: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[AsyncAITTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -138,13 +123,27 @@ class AsyncAITTSService(AudioContextTTSService): api_key: Async API key. voice_id: UUID of the voice to use for synthesis. See docs for a full list: https://docs.async.com/list-voices-16699698e0 + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(voice=...)`` instead. + version: Async API version. url: WebSocket URL for Async TTS API. model: TTS model to use (e.g., "async_flash_v1.0"). + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(model=...)`` instead. + sample_rate: Audio sample rate. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -153,7 +152,32 @@ class AsyncAITTSService(AudioContextTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to the parent service. """ - params = params or AsyncAITTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AsyncAITTSSettings( + model="async_flash_v1.0", + voice=None, + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", AsyncAITTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", AsyncAITTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AsyncAITTSSettings) + if not settings: + default_settings.language = ( + self.language_to_service_language(params.language) if params.language else None + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -161,16 +185,7 @@ class AsyncAITTSService(AudioContextTTSService): pause_frame_processing=True, push_stop_frames=True, sample_rate=sample_rate, - settings=AsyncAITTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - ), + settings=default_settings, **kwargs, ) @@ -178,6 +193,11 @@ class AsyncAITTSService(AudioContextTTSService): self._api_version = version self._url = url + # Init-only audio format config (not runtime-updatable). + self._output_container = container + self._output_encoding = encoding + self._output_sample_rate = 0 # Set in start() + self._receive_task = None self._keepalive_task = None @@ -225,7 +245,7 @@ class AsyncAITTSService(AudioContextTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.output_sample_rate = self.sample_rate + self._output_sample_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -282,9 +302,9 @@ class AsyncAITTSService(AudioContextTTSService): "model_id": self._settings.model, "voice": {"mode": "id", "id": self._settings.voice}, "output_format": { - "container": self._settings.output_container, - "encoding": self._settings.output_encoding, - "sample_rate": self._settings.output_sample_rate, + "container": self._output_container, + "encoding": self._output_encoding, + "sample_rate": self._output_sample_rate, }, "language": self._settings.language, } @@ -471,6 +491,9 @@ class AsyncAIHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Async API. + .. deprecated:: 0.0.105 + Use ``AsyncAITTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -481,15 +504,16 @@ class AsyncAIHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "async_flash_v1.0", + model: Optional[str] = None, url: str = "https://api.async.com", version: str = "v1", sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[AsyncAITTSSettings] = None, **kwargs, ): """Initialize the Async TTS service. @@ -497,30 +521,60 @@ class AsyncAIHttpTTSService(TTSService): Args: api_key: Async API key. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(voice=...)`` instead. + aiohttp_session: An aiohttp session for making HTTP requests. model: TTS model to use (e.g., "async_flash_v1.0"). + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(model=...)`` instead. + url: Base URL for Async API. version: API version string for Async API. sample_rate: Audio sample rate. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=AsyncAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - params = params or AsyncAIHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AsyncAITTSSettings( + model="async_flash_v1.0", + voice=None, + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", AsyncAITTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", AsyncAITTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AsyncAITTSSettings) + if not settings: + default_settings.language = ( + self.language_to_service_language(params.language) if params.language else None + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AsyncAITTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - ), + settings=default_settings, **kwargs, ) @@ -528,6 +582,11 @@ class AsyncAIHttpTTSService(TTSService): self._base_url = url self._api_version = version + # Init-only audio format config (not runtime-updatable). + self._output_container = container + self._output_encoding = encoding + self._output_sample_rate = 0 # Set in start() + self._session = aiohttp_session def can_generate_metrics(self) -> bool: @@ -556,7 +615,7 @@ class AsyncAIHttpTTSService(TTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.output_sample_rate = self.sample_rate + self._output_sample_rate = self.sample_rate @traced_tts async def run_tts(self, text: str, context_id: str) -> AsyncGenerator[Frame, None]: @@ -579,9 +638,9 @@ class AsyncAIHttpTTSService(TTSService): "transcript": text, "voice": voice_config, "output_format": { - "container": self._settings.output_container, - "encoding": self._settings.output_encoding, - "sample_rate": self._settings.output_sample_rate, + "container": self._output_container, + "encoding": self._output_encoding, + "sample_rate": self._output_sample_rate, }, "language": self._settings.language, } diff --git a/src/pipecat/services/aws/llm.py b/src/pipecat/services/aws/llm.py index e465ae460..34a0dd780 100644 --- a/src/pipecat/services/aws/llm.py +++ b/src/pipecat/services/aws/llm.py @@ -55,7 +55,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.utils.tracing.service_decorators import traced_llm try: @@ -75,10 +75,12 @@ class AWSBedrockLLMSettings(LLMSettings): """Settings for AWS Bedrock LLM services. Parameters: + stop_sequences: List of strings that stop generation. latency: Performance mode - "standard" or "optimized". additional_model_request_fields: Additional model-specific parameters. """ + stop_sequences: List[str] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) latency: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) additional_model_request_fields: Dict[str, Any] | _NotGiven = field( default_factory=lambda: NOT_GIVEN @@ -752,6 +754,10 @@ class AWSBedrockLLMService(LLMService): class InputParams(BaseModel): """Input parameters for AWS Bedrock LLM service. + .. deprecated:: + Use ``AWSBedrockLLMSettings`` instead. Pass settings directly via the + ``settings`` parameter of :class:`AWSBedrockLLMService`. + Parameters: max_tokens: Maximum number of tokens to generate. temperature: Sampling temperature between 0.0 and 1.0. @@ -771,55 +777,96 @@ class AWSBedrockLLMService(LLMService): def __init__( self, *, - model: str, + model: Optional[str] = None, aws_access_key: Optional[str] = None, aws_secret_key: Optional[str] = None, aws_session_token: Optional[str] = None, aws_region: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[AWSBedrockLLMSettings] = None, + stop_sequences: Optional[List[str]] = None, client_config: Optional[Config] = None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, - system_instruction: Optional[str] = None, **kwargs, ): """Initialize the AWS Bedrock LLM service. Args: model: The AWS Bedrock model identifier to use. + + .. deprecated:: + Use ``settings=AWSBedrockLLMSettings(model=...)`` instead. + aws_access_key: AWS access key ID. If None, uses default credentials. aws_secret_key: AWS secret access key. If None, uses default credentials. aws_session_token: AWS session token for temporary credentials. aws_region: AWS region for the Bedrock service. params: Model parameters and configuration. + + .. deprecated:: + Use ``settings=AWSBedrockLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. + stop_sequences: List of strings that stop generation. + + .. deprecated:: 0.0.105 + Use ``settings=AWSBedrockLLMSettings(stop_sequences=...)`` instead. + client_config: Custom boto3 client configuration. retry_timeout_secs: Request timeout in seconds for retry logic. retry_on_timeout: Whether to retry the request once if it times out. - system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - params = params or AWSBedrockLLMService.InputParams() - - super().__init__( - settings=AWSBedrockLLMSettings( - model=model, - max_tokens=params.max_tokens, - temperature=params.temperature, - top_p=params.top_p, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - latency=params.latency, - additional_model_request_fields=params.additional_model_request_fields - if isinstance(params.additional_model_request_fields, dict) - else {}, - ), - **kwargs, + # 1. Initialize default_settings with hardcoded defaults + default_settings = AWSBedrockLLMSettings( + model="us.amazon.nova-lite-v1:0", + system_instruction=None, + max_tokens=None, + temperature=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + stop_sequences=None, + latency=None, + additional_model_request_fields={}, ) + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", AWSBedrockLLMSettings, "model") + default_settings.model = model + if stop_sequences is not None: + _warn_deprecated_param("stop_sequences", AWSBedrockLLMSettings, "stop_sequences") + default_settings.stop_sequences = stop_sequences + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AWSBedrockLLMSettings) + if not settings: + default_settings.max_tokens = params.max_tokens + default_settings.temperature = params.temperature + default_settings.top_p = params.top_p + if params.stop_sequences: + default_settings.stop_sequences = params.stop_sequences + default_settings.latency = params.latency + if isinstance(params.additional_model_request_fields, dict): + default_settings.additional_model_request_fields = ( + params.additional_model_request_fields + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) + # Initialize the AWS Bedrock client if not client_config: client_config = Config( @@ -841,11 +888,10 @@ class AWSBedrockLLMService(LLMService): self._retry_timeout_secs = retry_timeout_secs self._retry_on_timeout = retry_on_timeout - self._system_instruction = system_instruction - logger.info(f"Using AWS Bedrock model: {model}") - if self._system_instruction: - logger.debug(f"{self}: Using system instruction: {self._system_instruction}") + logger.info(f"Using AWS Bedrock model: {self._settings.model}") + if self._settings.system_instruction: + logger.debug(f"{self}: Using system instruction: {self._settings.system_instruction}") def can_generate_metrics(self) -> bool: """Check if the service can generate usage metrics. @@ -871,6 +917,8 @@ class AWSBedrockLLMService(LLMService): inference_config["temperature"] = self._settings.temperature if self._settings.top_p is not None: inference_config["topP"] = self._settings.top_p + if self._settings.stop_sequences: + inference_config["stopSequences"] = self._settings.stop_sequences return inference_config async def run_inference( @@ -1024,13 +1072,13 @@ class AWSBedrockLLMService(LLMService): if isinstance(context, LLMContext): adapter: AWSBedrockLLMAdapter = self.get_llm_adapter() params: AWSBedrockLLMInvocationParams = adapter.get_llm_invocation_params(context) - if self._system_instruction: + if self._settings.system_instruction: if params["system"]: logger.warning( f"{self}: Both system_instruction and a system message in context are" " set. Using system_instruction." ) - params["system"] = [{"text": self._system_instruction}] + params["system"] = [{"text": self._settings.system_instruction}] return params # AWS Bedrock-specific context diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index 29612e593..fd13fe56e 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -60,7 +60,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.utils.time import time_now_iso8601 try: @@ -191,12 +191,12 @@ class AWSNovaSonicLLMSettings(LLMSettings): """Settings for AWS Nova Sonic LLM service. Parameters: - voice_id: Voice for speech synthesis. + voice: Voice identifier for speech synthesis. endpointing_sensitivity: Controls how quickly Nova Sonic decides the user has stopped speaking. Can be "LOW", "MEDIUM", or "HIGH". """ - voice_id: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) endpointing_sensitivity: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -222,6 +222,7 @@ class AWSNovaSonicLLMService(LLMService): model: str = "amazon.nova-2-sonic-v1:0", voice_id: str = "matthew", params: Optional[Params] = None, + settings: Optional[AWSNovaSonicLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[ToolsSchema] = None, send_transcription_frames: bool = True, @@ -238,13 +239,31 @@ class AWSNovaSonicLLMService(LLMService): - Nova 2 Sonic (the default model): "us-east-1", "us-west-2", "ap-northeast-1" - Nova Sonic (the older model): "us-east-1", "ap-northeast-1" model: Model identifier. Defaults to "amazon.nova-2-sonic-v1:0". + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(model=...)`` instead. + voice_id: Voice ID for speech synthesis. Note that some voices are designed for use with a specific language. Options: - Nova 2 Sonic (the default model): see https://docs.aws.amazon.com/nova/latest/nova2-userguide/sonic-language-support.html - Nova Sonic (the older model): see https://docs.aws.amazon.com/nova/latest/userguide/available-voices.html. + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(voice=...)`` instead. + params: Model parameters for audio configuration and inference. + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(...)`` instead. + + settings: AWS Nova Sonic LLM settings. If provided together with + deprecated top-level parameters, the ``settings`` values take + precedence. system_instruction: System-level instruction for the model. + + .. deprecated:: 0.0.105 + Use ``settings=AWSNovaSonicLLMSettings(system_instruction=...)`` instead. tools: Available tools/functions for the model to use. send_transcription_frames: Whether to emit transcription frames. @@ -254,23 +273,51 @@ class AWSNovaSonicLLMService(LLMService): **kwargs: Additional arguments passed to the parent LLMService. """ - params = params or Params() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AWSNovaSonicLLMSettings( + model="amazon.nova-2-sonic-v1:0", + system_instruction=None, + voice="matthew", + temperature=0.7, + max_tokens=1024, + top_p=0.9, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + endpointing_sensitivity=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model != "amazon.nova-2-sonic-v1:0": + _warn_deprecated_param("model", AWSNovaSonicLLMSettings, "model") + default_settings.model = model + if voice_id != "matthew": + _warn_deprecated_param("voice_id", AWSNovaSonicLLMSettings, "voice") + default_settings.voice = voice_id + if system_instruction is not None: + _warn_deprecated_param( + "system_instruction", AWSNovaSonicLLMSettings, "system_instruction" + ) + default_settings.system_instruction = system_instruction + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AWSNovaSonicLLMSettings) + if not settings: + default_settings.temperature = params.temperature + default_settings.max_tokens = params.max_tokens + default_settings.top_p = params.top_p + default_settings.endpointing_sensitivity = params.endpointing_sensitivity + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=AWSNovaSonicLLMSettings( - model=model, - voice_id=voice_id, - temperature=params.temperature, - max_tokens=params.max_tokens, - top_p=params.top_p, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - endpointing_sensitivity=params.endpointing_sensitivity, - ), + settings=default_settings, **kwargs, ) self._secret_access_key = secret_access_key @@ -280,13 +327,13 @@ class AWSNovaSonicLLMService(LLMService): self._client: Optional[BedrockRuntimeClient] = None # Audio I/O config (hardware settings, not runtime-tunable) - self._input_sample_rate = params.input_sample_rate - self._input_sample_size = params.input_sample_size - self._input_channel_count = params.input_channel_count - self._output_sample_rate = params.output_sample_rate - self._output_sample_size = params.output_sample_size - self._output_channel_count = params.output_channel_count - self._system_instruction = system_instruction + _audio_params = params or Params() + self._input_sample_rate = _audio_params.input_sample_rate + self._input_sample_size = _audio_params.input_sample_size + self._input_channel_count = _audio_params.input_channel_count + self._output_sample_rate = _audio_params.output_sample_rate + self._output_sample_size = _audio_params.output_sample_size + self._output_channel_count = _audio_params.output_channel_count self._tools = tools # Validate endpointing_sensitivity parameter @@ -295,7 +342,7 @@ class AWSNovaSonicLLMService(LLMService): and not self._is_endpointing_sensitivity_supported() ): logger.warning( - f"endpointing_sensitivity is not supported for model '{model}' and will be ignored. " + f"endpointing_sensitivity is not supported for model '{self._settings.model}' and will be ignored. " "This parameter is only supported starting with Nova 2 Sonic (amazon.nova-2-sonic-v1:0)." ) self._settings.endpointing_sensitivity = None @@ -586,11 +633,11 @@ class AWSNovaSonicLLMService(LLMService): await self._send_prompt_start_event(tools) # Send system instruction. - # Instruction from context takes priority over self._system_instruction. + # Instruction from context takes priority over self._settings.system_instruction. system_instruction = ( llm_connection_params["system_instruction"] if llm_connection_params["system_instruction"] - else self._system_instruction + else self._settings.system_instruction ) logger.debug(f"Using system instruction: {system_instruction}") if system_instruction: @@ -772,7 +819,7 @@ class AWSNovaSonicLLMService(LLMService): "sampleRateHertz": {self._output_sample_rate}, "sampleSizeBits": {self._output_sample_size}, "channelCount": {self._output_channel_count}, - "voiceId": "{self._settings.voice_id}", + "voiceId": "{self._settings.voice}", "encoding": "base64", "audioType": "SPEECH" }}{tools_config} diff --git a/src/pipecat/services/aws/stt.py b/src/pipecat/services/aws/stt.py index 7c3fb398e..f46f5259c 100644 --- a/src/pipecat/services/aws/stt.py +++ b/src/pipecat/services/aws/stt.py @@ -14,7 +14,7 @@ import json import os import random import string -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -29,7 +29,7 @@ from pipecat.frames.frames import ( TranscriptionFrame, ) from pipecat.services.aws.utils import build_event_message, decode_event, get_presigned_url -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import STTSettings, _warn_deprecated_param from pipecat.services.stt_latency import AWS_TRANSCRIBE_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -47,21 +47,9 @@ except ModuleNotFoundError as e: @dataclass class AWSTranscribeSTTSettings(STTSettings): - """Settings for the AWS Transcribe STT service. + """Settings for the AWS Transcribe STT service.""" - Parameters: - sample_rate: Audio sample rate in Hz (8000 or 16000). - media_encoding: Audio encoding format (e.g. "linear16"). - number_of_channels: Number of audio channels. - show_speaker_label: Whether to show speaker labels. - enable_channel_identification: Whether to enable channel identification. - """ - - sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - media_encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - number_of_channels: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - show_speaker_label: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - enable_channel_identification: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class AWSTranscribeSTTService(WebsocketSTTService): @@ -81,8 +69,9 @@ class AWSTranscribeSTTService(WebsocketSTTService): aws_access_key_id: Optional[str] = None, aws_session_token: Optional[str] = None, region: Optional[str] = None, - sample_rate: int = 16000, - language: Language = Language.EN, + sample_rate: Optional[int] = None, + language: Optional[Language] = None, + settings: Optional[AWSTranscribeSTTSettings] = None, ttfs_p99_latency: Optional[float] = AWS_TRANSCRIBE_TTFS_P99, **kwargs, ): @@ -93,31 +82,49 @@ class AWSTranscribeSTTService(WebsocketSTTService): aws_access_key_id: AWS access key ID. If None, uses AWS_ACCESS_KEY_ID environment variable. aws_session_token: AWS session token for temporary credentials. If None, uses AWS_SESSION_TOKEN environment variable. region: AWS region for the service. - sample_rate: Audio sample rate in Hz. Must be 8000 or 16000. Defaults to 16000. - language: Language for transcription. Defaults to English. + sample_rate: Audio sample rate in Hz. If None, uses the pipeline sample rate. + AWS Transcribe only supports 8000 or 16000 Hz; other values are + clamped to 16000 Hz at connect time. + language: Language for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=AWSTranscribeSTTSettings(language=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = AWSTranscribeSTTSettings( + model=None, + language=self.language_to_service_language(Language.EN) or "en-US", + ) + + # 2. Apply direct init arg overrides (deprecated) + if language is not None: + _warn_deprecated_param("language", AWSTranscribeSTTSettings, "language") + default_settings.language = self.language_to_service_language(language) or "en-US" + + # 3. No params to apply + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( + sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=AWSTranscribeSTTSettings( - language=self.language_to_service_language(language) or "en-US", - sample_rate=sample_rate, - media_encoding="linear16", - number_of_channels=1, - show_speaker_label=False, - enable_channel_identification=False, - ), + settings=default_settings, **kwargs, ) - # Validate sample rate - AWS Transcribe only supports 8000 Hz or 16000 Hz - if sample_rate not in [8000, 16000]: - logger.warning( - f"AWS Transcribe only supports 8000 Hz or 16000 Hz sample rates. Converting from {sample_rate} Hz to 16000 Hz." - ) - self._settings.sample_rate = 16000 + # Init-only connection config (not runtime-updatable). + self._media_encoding = "linear16" + self._number_of_channels = 1 + self._show_speaker_label = False + self._enable_channel_identification = False self._credentials = { "aws_access_key_id": aws_access_key_id or os.getenv("AWS_ACCESS_KEY_ID"), @@ -265,6 +272,15 @@ class AWSTranscribeSTTService(WebsocketSTTService): if not language_code: raise ValueError(f"Unsupported language: {language_code}") + # Validate sample rate — AWS Transcribe only supports 8000 or 16000 Hz + connect_sample_rate = self.sample_rate + if connect_sample_rate not in (8000, 16000): + logger.warning( + f"AWS Transcribe only supports 8000 Hz or 16000 Hz sample rates. " + f"Converting from {connect_sample_rate} Hz to 16000 Hz." + ) + connect_sample_rate = 16000 + # Generate random websocket key websocket_key = "".join( random.choices( @@ -290,14 +306,14 @@ class AWSTranscribeSTTService(WebsocketSTTService): }, language_code=language_code, media_encoding=self.get_service_encoding( - self._settings.media_encoding + self._media_encoding ), # Convert to AWS format - sample_rate=self._settings.sample_rate, - number_of_channels=self._settings.number_of_channels, + sample_rate=connect_sample_rate, + number_of_channels=self._number_of_channels, enable_partial_results_stabilization=True, partial_results_stability="high", - show_speaker_label=self._settings.show_speaker_label, - enable_channel_identification=self._settings.enable_channel_identification, + show_speaker_label=self._show_speaker_label, + enable_channel_identification=self._enable_channel_identification, ) logger.debug(f"{self} Connecting to WebSocket with URL: {presigned_url[:100]}...") diff --git a/src/pipecat/services/aws/tts.py b/src/pipecat/services/aws/tts.py index 017477a7a..043fc264e 100644 --- a/src/pipecat/services/aws/tts.py +++ b/src/pipecat/services/aws/tts.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -155,6 +155,9 @@ class AWSPollyTTSService(TTSService): class InputParams(BaseModel): """Input parameters for AWS Polly TTS configuration. + .. deprecated:: 0.0.105 + Use ``AWSPollyTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: engine: TTS engine to use ('standard', 'neural', etc.). language: Language for synthesis. Defaults to English. @@ -178,9 +181,10 @@ class AWSPollyTTSService(TTSService): aws_access_key_id: Optional[str] = None, aws_session_token: Optional[str] = None, region: Optional[str] = None, - voice_id: str = "Joanna", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[AWSPollyTTSSettings] = None, **kwargs, ): """Initializes the AWS Polly TTS service. @@ -191,26 +195,59 @@ class AWSPollyTTSService(TTSService): aws_session_token: AWS session token for temporary credentials. region: AWS region for Polly service. Defaults to 'us-east-1'. voice_id: Voice ID to use for synthesis. Defaults to 'Joanna'. + + .. deprecated:: 0.0.105 + Use ``settings=AWSPollyTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses service default. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=AWSPollyTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ - params = params or AWSPollyTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AWSPollyTTSSettings( + model=None, + voice="Joanna", + language="en-US", + engine=None, + pitch=None, + rate=None, + volume=None, + lexicon_names=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", AWSPollyTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AWSPollyTTSSettings) + if not settings: + default_settings.engine = params.engine + default_settings.language = ( + self.language_to_service_language(params.language) + if params.language + else "en-US" + ) + default_settings.pitch = params.pitch + default_settings.rate = params.rate + default_settings.volume = params.volume + default_settings.lexicon_names = params.lexicon_names + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AWSPollyTTSSettings( - model=None, - voice=voice_id, - engine=params.engine, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - volume=params.volume, - lexicon_names=params.lexicon_names, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/azure/image.py b/src/pipecat/services/azure/image.py index 66cc28504..28ac68bf9 100644 --- a/src/pipecat/services/azure/image.py +++ b/src/pipecat/services/azure/image.py @@ -12,15 +12,15 @@ using REST endpoints for creating images from text prompts. import asyncio import io -from dataclasses import dataclass -from typing import AsyncGenerator +from dataclasses import dataclass, field +from typing import AsyncGenerator, Optional import aiohttp from PIL import Image from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import NOT_GIVEN, ImageGenSettings, _NotGiven, _warn_deprecated_param @dataclass @@ -29,8 +29,11 @@ class AzureImageGenSettings(ImageGenSettings): Parameters: model: Azure image generation model identifier. + image_size: Target size for generated images. """ + image_size: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + class AzureImageGenServiceREST(ImageGenService): """Azure OpenAI REST-based image generation service. @@ -40,32 +43,63 @@ class AzureImageGenServiceREST(ImageGenService): and automatic image download and processing. """ + _settings: AzureImageGenSettings + def __init__( self, *, - image_size: str, + image_size: Optional[str] = None, api_key: str, endpoint: str, - model: str, + model: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, api_version="2023-06-01-preview", + settings: Optional[AzureImageGenSettings] = None, ): """Initialize the AzureImageGenServiceREST. Args: image_size: Size specification for generated images (e.g., "1024x1024"). + + .. deprecated:: 0.0.105 + Use ``settings=AzureImageGenSettings(image_size=...)`` instead. + api_key: Azure OpenAI API key for authentication. endpoint: Azure OpenAI endpoint URL. model: The image generation model to use. + + .. deprecated:: 0.0.105 + Use ``settings=AzureImageGenSettings(model=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. api_version: Azure API version string. Defaults to "2023-06-01-preview". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. """ - super().__init__(settings=AzureImageGenSettings(model=model)) + # 1. Initialize default_settings with hardcoded defaults + default_settings = AzureImageGenSettings( + model=None, + image_size=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", AzureImageGenSettings, "model") + default_settings.model = model + + if image_size is not None: + _warn_deprecated_param("image_size", AzureImageGenSettings, "image_size") + default_settings.image_size = image_size + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings) self._api_key = api_key self._azure_endpoint = endpoint self._api_version = api_version - self._image_size = image_size self._aiohttp_session = aiohttp_session async def run_image_gen(self, prompt: str) -> AsyncGenerator[Frame, None]: @@ -83,12 +117,13 @@ class AzureImageGenServiceREST(ImageGenService): headers = {"api-key": self._api_key, "Content-Type": "application/json"} body = { - # Enter your prompt text here "prompt": prompt, - "size": self._image_size, "n": 1, } + if self._settings.image_size is not None: + body["size"] = self._settings.image_size + async with self._aiohttp_session.post(url, headers=headers, json=body) as submission: # We never get past this line, because this header isn't # defined on a 429 response, but something is eating our diff --git a/src/pipecat/services/azure/llm.py b/src/pipecat/services/azure/llm.py index b1807ad13..5f1ce2698 100644 --- a/src/pipecat/services/azure/llm.py +++ b/src/pipecat/services/azure/llm.py @@ -6,10 +6,22 @@ """Azure OpenAI service implementation for the Pipecat AI framework.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger from openai import AsyncAzureOpenAI +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class AzureLLMSettings(OpenAILLMSettings): + """Settings for Azure OpenAI LLM service.""" + + pass class AzureLLMService(OpenAILLMService): @@ -24,8 +36,9 @@ class AzureLLMService(OpenAILLMService): *, api_key: str, endpoint: str, - model: str, + model: Optional[str] = None, api_version: str = "2024-09-01-preview", + settings: Optional[AzureLLMSettings] = None, **kwargs, ): """Initialize the Azure LLM service. @@ -33,15 +46,33 @@ class AzureLLMService(OpenAILLMService): Args: api_key: The API key for accessing Azure OpenAI. endpoint: The Azure endpoint URL. - model: The model identifier to use. + model: The model identifier to use. Defaults to "gpt-4o". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_version: Azure API version. Defaults to "2024-09-01-preview". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = AzureLLMSettings(model="gpt-4o") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", AzureLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + # Initialize variables before calling parent __init__() because that # will call create_client() and we need those values there. self._endpoint = endpoint self._api_version = api_version - super().__init__(api_key=api_key, model=model, **kwargs) + super().__init__(api_key=api_key, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Azure OpenAI endpoint. diff --git a/src/pipecat/services/azure/realtime/llm.py b/src/pipecat/services/azure/realtime/llm.py index 39c9bd707..0de2217d8 100644 --- a/src/pipecat/services/azure/realtime/llm.py +++ b/src/pipecat/services/azure/realtime/llm.py @@ -6,9 +6,11 @@ """Azure OpenAI Realtime LLM service implementation.""" +from dataclasses import dataclass + from loguru import logger -from pipecat.services.openai.realtime.llm import OpenAIRealtimeLLMService +from pipecat.services.openai.realtime.llm import OpenAIRealtimeLLMService, OpenAIRealtimeLLMSettings try: from websockets.asyncio.client import connect as websocket_connect @@ -18,6 +20,13 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +@dataclass +class AzureRealtimeLLMSettings(OpenAIRealtimeLLMSettings): + """Settings for Azure Realtime LLM service.""" + + pass + + class AzureRealtimeLLMService(OpenAIRealtimeLLMService): """Azure OpenAI Realtime LLM service with Azure-specific authentication. @@ -26,6 +35,8 @@ class AzureRealtimeLLMService(OpenAIRealtimeLLMService): real-time audio and text communication capabilities as the base OpenAI service. """ + _settings: AzureRealtimeLLMSettings + def __init__( self, *, diff --git a/src/pipecat/services/azure/stt.py b/src/pipecat/services/azure/stt.py index 5533e350e..8e6204c5e 100644 --- a/src/pipecat/services/azure/stt.py +++ b/src/pipecat/services/azure/stt.py @@ -11,7 +11,7 @@ Speech SDK for real-time audio transcription. """ import asyncio -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TranscriptionFrame, ) from pipecat.services.azure.common import language_to_azure_language -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import STTSettings, _warn_deprecated_param from pipecat.services.stt_latency import AZURE_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language @@ -53,15 +53,9 @@ except ModuleNotFoundError as e: @dataclass class AzureSTTSettings(STTSettings): - """Settings for the Azure STT service. + """Settings for the Azure STT service.""" - Parameters: - region: Azure region for the Speech service. - sample_rate: Audio sample rate in Hz. - """ - - region: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - sample_rate: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class AzureSTTService(STTService): @@ -79,10 +73,11 @@ class AzureSTTService(STTService): *, api_key: str, region: str, - language: Language = Language.EN_US, + language: Optional[Language] = Language.EN_US, sample_rate: Optional[int] = None, private_endpoint: Optional[str] = None, endpoint_id: Optional[str] = None, + settings: Optional[AzureSTTSettings] = None, ttfs_p99_latency: Optional[float] = AZURE_TTFS_P99, **kwargs, ): @@ -92,30 +87,49 @@ class AzureSTTService(STTService): api_key: Azure Cognitive Services subscription key. region: Azure region for the Speech service (e.g., 'eastus'). language: Language for speech recognition. Defaults to English (US). + + .. deprecated:: 0.0.105 + Use ``settings=AzureSTTSettings(language=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. private_endpoint: Private endpoint for STT behind firewall. See https://docs.azure.cn/en-us/ai-services/speech-service/speech-services-private-link?tabs=portal endpoint_id: Custom model endpoint id. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = AzureSTTSettings( + model=None, + language=language_to_azure_language(Language.EN_US), + ) + + # 2. Apply direct init arg overrides (deprecated) + if language is not None and language != Language.EN_US: + _warn_deprecated_param("language", AzureSTTSettings, "language") + default_settings.language = language_to_azure_language(language) + + # 3. No params to apply + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=AzureSTTSettings( - model=None, - region=region, - language=language_to_azure_language(language), - sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) self._speech_config = SpeechConfig( subscription=api_key, region=region, - speech_recognition_language=language_to_azure_language(language), + speech_recognition_language=default_settings.language + or language_to_azure_language(Language.EN_US), endpoint=private_endpoint, ) diff --git a/src/pipecat/services/azure/tts.py b/src/pipecat/services/azure/tts.py index 6e62c73bf..112459c5a 100644 --- a/src/pipecat/services/azure/tts.py +++ b/src/pipecat/services/azure/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.azure.common import language_to_azure_language -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TextAggregationMode, TTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -73,7 +73,6 @@ class AzureTTSSettings(TTSSettings): Parameters: emphasis: Emphasis level for speech ("strong", "moderate", "reduced"). - language: Language for synthesis. Defaults to English (US). pitch: Voice pitch adjustment (e.g., "+10%", "-5Hz", "high"). rate: Speech rate adjustment (e.g., "1.0", "1.25", "slow", "fast"). role: Voice role for expression (e.g., "YoungAdultFemale"). @@ -83,7 +82,6 @@ class AzureTTSSettings(TTSSettings): """ emphasis: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - language: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) pitch: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) rate: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) role: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -115,6 +113,9 @@ class AzureBaseTTSService: class InputParams(BaseModel): """Input parameters for Azure TTS voice configuration. + .. deprecated:: 0.0.105 + Use ``settings=AzureTTSSettings(...)`` instead. + Parameters: emphasis: Emphasis level for speech ("strong", "moderate", "reduced"). language: Language for synthesis. Defaults to English (US). @@ -140,7 +141,6 @@ class AzureBaseTTSService: *, api_key: str, region: str, - voice: str = "en-US-SaraNeural", ): """Initialize Azure-specific configuration. @@ -149,7 +149,6 @@ class AzureBaseTTSService: Args: api_key: Azure Cognitive Services subscription key. region: Azure region identifier (e.g., "eastus", "westus2"). - voice: Voice name to use for synthesis. Defaults to "en-US-SaraNeural". """ self._api_key = api_key self._region = region @@ -253,9 +252,10 @@ class AzureTTSService(TTSService, AzureBaseTTSService): *, api_key: str, region: str, - voice: str = "en-US-SaraNeural", + voice: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[AzureBaseTTSService.InputParams] = None, + settings: Optional[AzureTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -265,9 +265,19 @@ class AzureTTSService(TTSService, AzureBaseTTSService): Args: api_key: Azure Cognitive Services subscription key. region: Azure region identifier (e.g., "eastus", "westus2"). - voice: Voice name to use for synthesis. Defaults to "en-US-SaraNeural". + voice: Voice name to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=AzureTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. params: Voice and synthesis parameters configuration. + + .. deprecated:: 0.0.105 + Use ``settings=AzureTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -276,7 +286,45 @@ class AzureTTSService(TTSService, AzureBaseTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent WordTTSService. """ - params = params or AzureBaseTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AzureTTSSettings( + model=None, + voice="en-US-SaraNeural", + language="en-US", + emphasis=None, + pitch=None, + rate=None, + role=None, + style=None, + style_degree=None, + volume=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice is not None: + _warn_deprecated_param("voice", AzureTTSSettings, "voice") + default_settings.voice = voice + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AzureTTSSettings) + if not settings: + default_settings.emphasis = params.emphasis + default_settings.language = ( + self.language_to_service_language(params.language) + if params.language + else "en-US" + ) + default_settings.pitch = params.pitch + default_settings.rate = params.rate + default_settings.role = params.role + default_settings.style = params.style + default_settings.style_degree = params.style_degree + default_settings.volume = params.volume + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -286,25 +334,12 @@ class AzureTTSService(TTSService, AzureBaseTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=AzureTTSSettings( - model=None, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - role=params.role, - style=params.style, - style_degree=params.style_degree, - voice=voice, - volume=params.volume, - ), + settings=default_settings, **kwargs, ) # Initialize Azure-specific functionality from mixin - self._init_azure_base(api_key=api_key, region=region, voice=voice) + self._init_azure_base(api_key=api_key, region=region) self._speech_config = None self._speech_synthesizer = None @@ -730,9 +765,10 @@ class AzureHttpTTSService(TTSService, AzureBaseTTSService): *, api_key: str, region: str, - voice: str = "en-US-SaraNeural", + voice: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[AzureBaseTTSService.InputParams] = None, + settings: Optional[AzureTTSSettings] = None, **kwargs, ): """Initialize the Azure HTTP TTS service. @@ -740,34 +776,69 @@ class AzureHttpTTSService(TTSService, AzureBaseTTSService): Args: api_key: Azure Cognitive Services subscription key. region: Azure region identifier (e.g., "eastus", "westus2"). - voice: Voice name to use for synthesis. Defaults to "en-US-SaraNeural". + voice: Voice name to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=AzureTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. params: Voice and synthesis parameters configuration. + + .. deprecated:: 0.0.105 + Use ``settings=AzureTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or AzureBaseTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = AzureTTSSettings( + model=None, + voice="en-US-SaraNeural", + language="en-US", + emphasis=None, + pitch=None, + rate=None, + role=None, + style=None, + style_degree=None, + volume=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice is not None: + _warn_deprecated_param("voice", AzureTTSSettings, "voice") + default_settings.voice = voice + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", AzureTTSSettings) + if not settings: + default_settings.emphasis = params.emphasis + default_settings.language = ( + self.language_to_service_language(params.language) + if params.language + else "en-US" + ) + default_settings.pitch = params.pitch + default_settings.rate = params.rate + default_settings.role = params.role + default_settings.style = params.style + default_settings.style_degree = params.style_degree + default_settings.volume = params.volume + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AzureTTSSettings( - model=None, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - role=params.role, - style=params.style, - style_degree=params.style_degree, - voice=voice, - volume=params.volume, - ), + settings=default_settings, **kwargs, ) # Initialize Azure-specific functionality from mixin - self._init_azure_base(api_key=api_key, region=region, voice=voice) + self._init_azure_base(api_key=api_key, region=region) self._speech_config = None self._speech_synthesizer = None diff --git a/src/pipecat/services/camb/tts.py b/src/pipecat/services/camb/tts.py index 75b299569..ef007181e 100644 --- a/src/pipecat/services/camb/tts.py +++ b/src/pipecat/services/camb/tts.py @@ -32,7 +32,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -175,6 +175,9 @@ class CambTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Camb.ai TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=CambTTSSettings(...)`` instead. + Parameters: language: Language for synthesis (BCP-47 format). Defaults to English. user_instructions: Custom instructions for mars-instruct model only. @@ -193,47 +196,82 @@ class CambTTSService(TTSService): self, *, api_key: str, - voice_id: int = 147320, - model: str = "mars-flash", + voice_id: Optional[int] = None, + model: Optional[str] = None, timeout: float = 60.0, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[CambTTSSettings] = None, **kwargs, ): """Initialize the Camb.ai TTS service. Args: api_key: Camb.ai API key for authentication. - voice_id: Voice ID to use. Defaults to 147320. + voice_id: Voice ID to use. + + .. deprecated:: 0.0.105 + Use ``settings=CambTTSSettings(voice=...)`` instead. + model: TTS model to use. Options: "mars-flash" (fast), "mars-pro" (high quality). - Defaults to "mars-flash". + + .. deprecated:: 0.0.105 + Use ``settings=CambTTSSettings(model=...)`` instead. + timeout: Request timeout in seconds. Defaults to 60.0 (minimum recommended by Camb.ai). sample_rate: Audio sample rate in Hz. If None, uses model-specific default. params: Additional voice parameters. If None, uses defaults. + + .. deprecated:: 0.0.105 + Use ``settings=CambTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or CambTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = CambTTSSettings( + model="mars-flash", + voice=147320, + language="en-us", + user_instructions=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", CambTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", CambTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", CambTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = ( + self.language_to_service_language(params.language) or "en-us" + ) + if params.user_instructions is not None: + default_settings.user_instructions = params.user_instructions + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) # Warn if sample rate doesn't match model's supported rate - if sample_rate and sample_rate != MODEL_SAMPLE_RATES.get(model): + _model = default_settings.model + if sample_rate and sample_rate != MODEL_SAMPLE_RATES.get(_model): logger.warning( - f"Camb.ai's {model} model only supports {MODEL_SAMPLE_RATES.get(model)}Hz " + f"Camb.ai's {_model} model only supports {MODEL_SAMPLE_RATES.get(_model)}Hz " f"sample rate. Current rate of {sample_rate}Hz may cause issues." ) super().__init__( sample_rate=sample_rate, - settings=CambTTSSettings( - model=model, - voice=voice_id, - language=( - self.language_to_service_language(params.language) - if params.language - else "en-us" - ), - user_instructions=params.user_instructions, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/cartesia/stt.py b/src/pipecat/services/cartesia/stt.py index 526fc9116..67416016e 100644 --- a/src/pipecat/services/cartesia/stt.py +++ b/src/pipecat/services/cartesia/stt.py @@ -12,7 +12,7 @@ the Cartesia Live transcription API for real-time speech recognition. import json import urllib.parse -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -28,7 +28,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import STTSettings, _warn_deprecated_param from pipecat.services.stt_latency import CARTESIA_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language @@ -46,20 +46,17 @@ except ModuleNotFoundError as e: @dataclass class CartesiaSTTSettings(STTSettings): - """Settings for the Cartesia STT service. + """Settings for the Cartesia STT service.""" - Parameters: - encoding: Audio encoding format (e.g. ``"pcm_s16le"``). - """ - - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class CartesiaLiveOptions: """Configuration options for Cartesia Live STT service. - Manages transcription parameters including model selection, language, - audio encoding format, and sample rate settings. + .. deprecated:: 0.0.105 + Use ``settings=CartesiaSTTSettings(...)`` for model/language and + direct ``__init__`` parameters for encoding/sample_rate instead. """ def __init__( @@ -156,8 +153,10 @@ class CartesiaSTTService(WebsocketSTTService): *, api_key: str, base_url: str = "", - sample_rate: int = 16000, + encoding: str = "pcm_s16le", + sample_rate: Optional[int] = None, live_options: Optional[CartesiaLiveOptions] = None, + settings: Optional[CartesiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = CARTESIA_TTFS_P99, **kwargs, ): @@ -166,39 +165,51 @@ class CartesiaSTTService(WebsocketSTTService): Args: api_key: Authentication key for Cartesia API. base_url: Custom API endpoint URL. If empty, uses default. - sample_rate: Audio sample rate in Hz. Defaults to 16000. + encoding: Audio encoding format. Defaults to "pcm_s16le". + sample_rate: Audio sample rate in Hz. If None, uses the pipeline + sample rate. live_options: Configuration options for transcription service. + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaSTTSettings(...)`` for model/language + and direct init parameters for encoding/sample_rate instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService. """ - sample_rate = sample_rate or (live_options.sample_rate if live_options else None) - - default_options = CartesiaLiveOptions( + # 1. Initialize default_settings with hardcoded defaults + default_settings = CartesiaSTTSettings( model="ink-whisper", language=Language.EN.value, - encoding="pcm_s16le", - sample_rate=sample_rate, ) - merged_options = default_options.to_dict() - if live_options: - merged_options.update(live_options.to_dict()) - # Filter out "None" string values - merged_options = { - k: v for k, v in merged_options.items() if not isinstance(v, str) or v != "None" - } + # 2. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", CartesiaSTTSettings) + if not settings: + if live_options.sample_rate and sample_rate is None: + sample_rate = live_options.sample_rate + if live_options.encoding: + encoding = live_options.encoding + if live_options.model: + default_settings.model = live_options.model + if live_options.language: + lang = live_options.language + default_settings.language = lang.value if isinstance(lang, Language) else lang + + # 3. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=120, keepalive_interval=30, - settings=CartesiaSTTSettings( - model=merged_options["model"], - language=merged_options.get("language"), - encoding=merged_options.get("encoding", "pcm_s16le"), - ), + settings=default_settings, **kwargs, ) @@ -206,6 +217,9 @@ class CartesiaSTTService(WebsocketSTTService): self._base_url = base_url or "api.cartesia.ai" self._receive_task = None + # Init-only audio config (not runtime-updatable). + self._encoding = encoding + def can_generate_metrics(self) -> bool: """Check if the service can generate processing metrics. @@ -324,7 +338,7 @@ class CartesiaSTTService(WebsocketSTTService): params = { "model": self._settings.model, "language": self._settings.language, - "encoding": self._settings.encoding, + "encoding": self._encoding, "sample_rate": str(self.sample_rate), } ws_url = f"wss://{self._base_url}/stt/websocket?{urllib.parse.urlencode(params)}" diff --git a/src/pipecat/services/cartesia/tts.py b/src/pipecat/services/cartesia/tts.py index a096a36b3..166aa70af 100644 --- a/src/pipecat/services/cartesia/tts.py +++ b/src/pipecat/services/cartesia/tts.py @@ -8,14 +8,13 @@ import base64 import json -import warnings from dataclasses import dataclass, field from enum import Enum -from typing import Any, AsyncGenerator, List, Literal, Mapping, Optional +from typing import AsyncGenerator, List, Optional import aiohttp from loguru import logger -from pydantic import BaseModel, Field +from pydantic import BaseModel from pipecat.frames.frames import ( CancelFrame, @@ -27,7 +26,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.text.base_text_aggregator import BaseTextAggregator @@ -192,35 +191,16 @@ class CartesiaTTSSettings(TTSSettings): """Settings for Cartesia TTS services. Parameters: - output_container: Audio container format (e.g. "raw"). - output_encoding: Audio encoding format (e.g. "pcm_s16le"). - output_sample_rate: Audio sample rate in Hz. - speed: Voice speed control for non-Sonic-3 models (literal values). - emotion: List of emotion controls for non-Sonic-3 models. generation_config: Generation configuration for Sonic-3 models. Includes volume, speed (numeric), and emotion (string) parameters. pronunciation_dict_id: The ID of the pronunciation dictionary to use for custom pronunciations. """ - output_container: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - speed: Literal["slow", "normal", "fast"] | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - emotion: List[str] | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - generation_config: GenerationConfig | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - pronunciation_dict_id: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - - @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "CartesiaTTSSettings": - """Construct settings from a plain dict, destructuring legacy nested ``output_format``.""" - flat = dict(settings) - nested = flat.pop("output_format", None) - if isinstance(nested, dict): - flat.setdefault("output_container", nested.get("container")) - flat.setdefault("output_encoding", nested.get("encoding")) - flat.setdefault("output_sample_rate", nested.get("sample_rate")) - return super().from_mapping(flat) + generation_config: GenerationConfig | None | _NotGiven = field( + default_factory=lambda: NOT_GIVEN + ) + pronunciation_dict_id: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class CartesiaTTSService(AudioContextTTSService): @@ -228,7 +208,7 @@ class CartesiaTTSService(AudioContextTTSService): Provides text-to-speech using Cartesia's streaming WebSocket API. Supports word-level timestamps, audio context management, and various voice - customization options including speed and emotion controls. + customization options including generation configuration. """ _settings: CartesiaTTSSettings @@ -238,20 +218,12 @@ class CartesiaTTSService(AudioContextTTSService): Parameters: language: Language to use for synthesis. - speed: Voice speed control for non-Sonic-3 models (literal values). - emotion: List of emotion controls for non-Sonic-3 models. - - .. deprecated:: 0.0.68 - The `emotion` parameter is deprecated and will be removed in a future version. - generation_config: Generation configuration for Sonic-3 models. Includes volume, speed (numeric), and emotion (string) parameters. pronunciation_dict_id: The ID of the pronunciation dictionary to use for custom pronunciations. """ language: Optional[Language] = Language.EN - speed: Optional[Literal["slow", "normal", "fast"]] = None - emotion: Optional[List[str]] = [] generation_config: Optional[GenerationConfig] = None pronunciation_dict_id: Optional[str] = None @@ -259,14 +231,15 @@ class CartesiaTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, cartesia_version: str = "2025-04-16", url: str = "wss://api.cartesia.ai/tts/websocket", - model: str = "sonic-3", + model: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[CartesiaTTSSettings] = None, text_aggregator: Optional[BaseTextAggregator] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, @@ -277,13 +250,27 @@ class CartesiaTTSService(AudioContextTTSService): Args: api_key: Cartesia API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(voice=...)`` instead. + cartesia_version: API version string for Cartesia service. url: WebSocket URL for Cartesia TTS API. model: TTS model to use (e.g., "sonic-3"). + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate. If None, uses default. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregator: Custom text aggregator for processing input text. .. deprecated:: 0.0.95 @@ -310,7 +297,38 @@ class CartesiaTTSService(AudioContextTTSService): # if we're interrupted. Cartesia gives us word-by-word timestamps. We # can use those to generate text frames ourselves aligned with the # playout timing of the audio! - params = params or CartesiaTTSService.InputParams() + + # 1. Initialize default_settings with hardcoded defaults + default_settings = CartesiaTTSSettings( + model="sonic-3", + voice=None, + language=language_to_cartesia_language(Language.EN), + generation_config=None, + pronunciation_dict_id=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", CartesiaTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", CartesiaTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", CartesiaTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.generation_config is not None: + default_settings.generation_config = params.generation_config + if params.pronunciation_dict_id is not None: + default_settings.pronunciation_dict_id = params.pronunciation_dict_id + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -320,20 +338,7 @@ class CartesiaTTSService(AudioContextTTSService): supports_word_timestamps=True, sample_rate=sample_rate, text_aggregator=text_aggregator, - settings=CartesiaTTSSettings( - model=model, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - speed=params.speed, - emotion=params.emotion, - generation_config=params.generation_config, - pronunciation_dict_id=params.pronunciation_dict_id, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -351,6 +356,11 @@ class CartesiaTTSService(AudioContextTTSService): self._cartesia_version = cartesia_version self._url = url + # Audio output format — init-only, not runtime-updatable + self._output_container = container + self._output_encoding = encoding + self._output_sample_rate = 0 # Set in start() from self.sample_rate + self._receive_task = None def can_generate_metrics(self) -> bool: @@ -448,17 +458,6 @@ class CartesiaTTSService(AudioContextTTSService): voice_config["mode"] = "id" voice_config["id"] = self._settings.voice - if self._settings.emotion: - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "The 'emotion' parameter in __experimental_controls is deprecated and will be removed in a future version.", - DeprecationWarning, - stacklevel=2, - ) - voice_config["__experimental_controls"] = {} - voice_config["__experimental_controls"]["emotion"] = self._settings.emotion - msg = { "transcript": text, "continue": continue_transcript, @@ -466,9 +465,9 @@ class CartesiaTTSService(AudioContextTTSService): "model_id": self._settings.model, "voice": voice_config, "output_format": { - "container": self._settings.output_container, - "encoding": self._settings.output_encoding, - "sample_rate": self._settings.output_sample_rate, + "container": self._output_container, + "encoding": self._output_encoding, + "sample_rate": self._output_sample_rate, }, "add_timestamps": add_timestamps, "use_original_timestamps": False if self._settings.model == "sonic" else True, @@ -477,9 +476,6 @@ class CartesiaTTSService(AudioContextTTSService): if self._settings.language: msg["language"] = self._settings.language - if self._settings.speed: - msg["speed"] = self._settings.speed - if self._settings.generation_config: msg["generation_config"] = self._settings.generation_config.model_dump( exclude_none=True @@ -497,7 +493,7 @@ class CartesiaTTSService(AudioContextTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.output_sample_rate = self.sample_rate + self._output_sample_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -692,20 +688,12 @@ class CartesiaHttpTTSService(TTSService): Parameters: language: Language to use for synthesis. - speed: Voice speed control for non-Sonic-3 models (literal values). - emotion: List of emotion controls for non-Sonic-3 models. - - .. deprecated:: 0.0.68 - The `emotion` parameter is deprecated and will be removed in a future version. - generation_config: Generation configuration for Sonic-3 models. Includes volume, speed (numeric), and emotion (string) parameters. pronunciation_dict_id: The ID of the pronunciation dictionary to use for custom pronunciations. """ language: Optional[Language] = Language.EN - speed: Optional[Literal["slow", "normal", "fast"]] = None - emotion: Optional[List[str]] = Field(default_factory=list) generation_config: Optional[GenerationConfig] = None pronunciation_dict_id: Optional[str] = None @@ -713,8 +701,8 @@ class CartesiaHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, - model: str = "sonic-3", + voice_id: Optional[str] = None, + model: Optional[str] = None, base_url: str = "https://api.cartesia.ai", cartesia_version: str = "2024-11-13", aiohttp_session: Optional[aiohttp.ClientSession] = None, @@ -722,6 +710,7 @@ class CartesiaHttpTTSService(TTSService): encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[CartesiaTTSSettings] = None, **kwargs, ): """Initialize the Cartesia HTTP TTS service. @@ -729,7 +718,15 @@ class CartesiaHttpTTSService(TTSService): Args: api_key: Cartesia API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(voice=...)`` instead. + model: TTS model to use (e.g., "sonic-3"). + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(model=...)`` instead. + base_url: Base URL for Cartesia HTTP API. cartesia_version: API version string for Cartesia service. aiohttp_session: Optional aiohttp ClientSession for HTTP requests. @@ -738,26 +735,49 @@ class CartesiaHttpTTSService(TTSService): encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=CartesiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - params = params or CartesiaHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = CartesiaTTSSettings( + model="sonic-3", + voice=None, + language=language_to_cartesia_language(Language.EN), + generation_config=None, + pronunciation_dict_id=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", CartesiaTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", CartesiaTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", CartesiaTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.generation_config is not None: + default_settings.generation_config = params.generation_config + if params.pronunciation_dict_id is not None: + default_settings.pronunciation_dict_id = params.pronunciation_dict_id + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=CartesiaTTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - speed=params.speed, - emotion=params.emotion, - generation_config=params.generation_config, - pronunciation_dict_id=params.pronunciation_dict_id, - ), + settings=default_settings, **kwargs, ) @@ -765,6 +785,11 @@ class CartesiaHttpTTSService(TTSService): self._base_url = base_url self._cartesia_version = cartesia_version + # Audio output format — init-only, not runtime-updatable + self._output_container = container + self._output_encoding = encoding + self._output_sample_rate = 0 # Set in start() from self.sample_rate + self._session: aiohttp.ClientSession | None = aiohttp_session self._owns_session = aiohttp_session is None @@ -794,7 +819,7 @@ class CartesiaHttpTTSService(TTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.output_sample_rate = self.sample_rate + self._output_sample_rate = self.sample_rate if self._owns_session: self._session = aiohttp.ClientSession() @@ -838,22 +863,12 @@ class CartesiaHttpTTSService(TTSService): try: voice_config = {"mode": "id", "id": self._settings.voice} - if self._settings.emotion: - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "The 'emotion' parameter in voice.__experimental_controls is deprecated and will be removed in a future version.", - DeprecationWarning, - stacklevel=2, - ) - voice_config["__experimental_controls"] = {"emotion": self._settings.emotion} - await self.start_ttfb_metrics() output_format = { - "container": self._settings.output_container, - "encoding": self._settings.output_encoding, - "sample_rate": self._settings.output_sample_rate, + "container": self._output_container, + "encoding": self._output_encoding, + "sample_rate": self._output_sample_rate, } payload = { @@ -866,9 +881,6 @@ class CartesiaHttpTTSService(TTSService): if self._settings.language: payload["language"] = self._settings.language - if self._settings.speed: - payload["speed"] = self._settings.speed - if self._settings.generation_config: payload["generation_config"] = self._settings.generation_config.model_dump( exclude_none=True diff --git a/src/pipecat/services/cerebras/llm.py b/src/pipecat/services/cerebras/llm.py index e1ecceef7..c3b56ff29 100644 --- a/src/pipecat/services/cerebras/llm.py +++ b/src/pipecat/services/cerebras/llm.py @@ -6,10 +6,22 @@ """Cerebras LLM service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class CerebrasLLMSettings(OpenAILLMSettings): + """Settings for Cerebras LLM service.""" + + pass class CerebrasLLMService(OpenAILLMService): @@ -19,12 +31,15 @@ class CerebrasLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: CerebrasLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.cerebras.ai/v1", - model: str = "gpt-oss-120b", + model: Optional[str] = None, + settings: Optional[CerebrasLLMSettings] = None, **kwargs, ): """Initialize the Cerebras LLM service. @@ -33,9 +48,27 @@ class CerebrasLLMService(OpenAILLMService): api_key: The API key for accessing Cerebras's API. base_url: The base URL for Cerebras API. Defaults to "https://api.cerebras.ai/v1". model: The model identifier to use. Defaults to "gpt-oss-120b". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = CerebrasLLMSettings(model="gpt-oss-120b") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", CerebrasLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Cerebras API endpoint. @@ -78,4 +111,12 @@ class CerebrasLLMService(OpenAILLMService): params.update(params_from_context) params.update(self._settings.extra) + + # Prepend system instruction if set + if self._settings.system_instruction: + messages = params.get("messages", []) + params["messages"] = [ + {"role": "system", "content": self._settings.system_instruction} + ] + messages + return params diff --git a/src/pipecat/services/deepgram/flux/stt.py b/src/pipecat/services/deepgram/flux/stt.py index 984906c6c..1e7f135b2 100644 --- a/src/pipecat/services/deepgram/flux/stt.py +++ b/src/pipecat/services/deepgram/flux/stt.py @@ -28,7 +28,7 @@ from pipecat.frames.frames import ( UserStartedSpeakingFrame, UserStoppedSpeakingFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 @@ -81,20 +81,16 @@ class DeepgramFluxSTTSettings(STTSettings): eot_timeout_ms: Time in ms after speech to finish a turn regardless of EOT confidence (default 5000). keyterm: Keyterms to boost recognition accuracy for specialized terminology. - mip_opt_out: Opt out of the Deepgram Model Improvement Program (default False). tag: Tags to label requests for identification during usage reporting. min_confidence: Minimum confidence required to create a TranscriptionFrame. - encoding: Audio encoding format (e.g. ``"linear16"``). """ eager_eot_threshold: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) eot_threshold: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) eot_timeout_ms: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) keyterm: list | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - mip_opt_out: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) tag: list | _NotGiven = field(default_factory=lambda: NOT_GIVEN) min_confidence: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class DeepgramFluxSTTService(WebsocketSTTService): @@ -124,8 +120,8 @@ class DeepgramFluxSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for Deepgram Flux API. - This class defines all available connection parameters for the Deepgram Flux API - based on the official documentation. + .. deprecated:: 0.0.105 + Use ``settings=DeepgramFluxSTTSettings(...)`` instead. Parameters: eager_eot_threshold: Optional. EagerEndOfTurn/TurnResumed are off by default. @@ -158,10 +154,12 @@ class DeepgramFluxSTTService(WebsocketSTTService): api_key: str, url: str = "wss://api.deepgram.com/v2/listen", sample_rate: Optional[int] = None, - model: str = "flux-general-en", + mip_opt_out: Optional[bool] = None, + model: Optional[str] = None, flux_encoding: str = "linear16", params: Optional[InputParams] = None, should_interrupt: bool = True, + settings: Optional[DeepgramFluxSTTSettings] = None, **kwargs, ): """Initialize the Deepgram Flux STT service. @@ -169,13 +167,24 @@ class DeepgramFluxSTTService(WebsocketSTTService): Args: api_key: Deepgram API key for authentication. Required for API access. url: WebSocket URL for the Deepgram Flux API. Defaults to the preview endpoint. - sample_rate: Audio sample rate in Hz. If None, uses the rate from params or 16000. - model: Deepgram Flux model to use for transcription. Currently only supports "flux-general-en". + sample_rate: Audio sample rate in Hz. If None, uses the pipeline + sample rate. + mip_opt_out: Opt out of the Deepgram Model Improvement Program. + model: Deepgram Flux model to use for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramFluxSTTSettings(model=...)`` instead. + flux_encoding: Audio encoding format required by Flux API. Must be "linear16". Raw signed little-endian 16-bit PCM encoding. params: InputParams instance containing detailed API configuration options. - If None, default parameters will be used. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramFluxSTTSettings(...)`` instead. + should_interrupt: Determine whether the bot should be interrupted when Flux detects that the user is speaking. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent WebsocketSTTService class. Examples: @@ -185,16 +194,15 @@ class DeepgramFluxSTTService(WebsocketSTTService): Advanced usage with custom parameters:: - params = DeepgramFluxSTTService.InputParams( - eager_eot_threshold=0.5, - eot_threshold=0.8, - keyterm=["AI", "machine learning", "neural network"], - tag=["production", "voice-agent"] - ) stt = DeepgramFluxSTTService( api_key="your-api-key", - model="flux-general-en", - params=params + settings=DeepgramFluxSTTSettings( + model="flux-general-en", + eager_eot_threshold=0.5, + eot_threshold=0.8, + keyterm=["AI", "machine learning", "neural network"], + tag=["production", "voice-agent"], + ), ) """ # Note: For DeepgramFluxSTTService, differently from other processes, we need to create @@ -207,29 +215,55 @@ class DeepgramFluxSTTService(WebsocketSTTService): # was never destroyed. # So we can keep it here as false, because inside the method send_with_retry, it will # already try to reconnect if needed. - params = params or DeepgramFluxSTTService.InputParams() + + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepgramFluxSTTSettings( + model="flux-general-en", + language=Language.EN, + eager_eot_threshold=None, + eot_threshold=None, + eot_timeout_ms=None, + keyterm=[], + tag=[], + min_confidence=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", DeepgramFluxSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", DeepgramFluxSTTSettings) + if not settings: + default_settings.eager_eot_threshold = params.eager_eot_threshold + default_settings.eot_threshold = params.eot_threshold + default_settings.eot_timeout_ms = params.eot_timeout_ms + default_settings.keyterm = params.keyterm or [] + default_settings.tag = params.tag or [] + default_settings.min_confidence = params.min_confidence + if params.mip_opt_out is not None: + mip_opt_out = params.mip_opt_out + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, reconnect_on_error=False, - settings=DeepgramFluxSTTSettings( - model=model, - language=Language.EN, - encoding=flux_encoding, - eager_eot_threshold=params.eager_eot_threshold, - eot_threshold=params.eot_threshold, - eot_timeout_ms=params.eot_timeout_ms, - keyterm=params.keyterm or [], - mip_opt_out=params.mip_opt_out, - tag=params.tag or [], - min_confidence=params.min_confidence, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._url = url self._should_interrupt = should_interrupt + self._encoding = flux_encoding + self._mip_opt_out = mip_opt_out self._websocket_url = None self._receive_task = None + # Flux event handlers self._register_event_handler("on_start_of_turn") self._register_event_handler("on_turn_resumed") @@ -415,7 +449,7 @@ class DeepgramFluxSTTService(WebsocketSTTService): url_params = [ f"model={self._settings.model}", f"sample_rate={self.sample_rate}", - f"encoding={self._settings.encoding}", + f"encoding={self._encoding}", ] if self._settings.eager_eot_threshold is not None: @@ -427,8 +461,8 @@ class DeepgramFluxSTTService(WebsocketSTTService): if self._settings.eot_timeout_ms is not None: url_params.append(f"eot_timeout_ms={self._settings.eot_timeout_ms}") - if self._settings.mip_opt_out is not None: - url_params.append(f"mip_opt_out={str(self._settings.mip_opt_out).lower()}") + if self._mip_opt_out is not None: + url_params.append(f"mip_opt_out={str(self._mip_opt_out).lower()}") # Add keyterm parameters (can have multiple) for keyterm in self._settings.keyterm: diff --git a/src/pipecat/services/deepgram/sagemaker/stt.py b/src/pipecat/services/deepgram/sagemaker/stt.py index 24a25e5fd..4f29b227f 100644 --- a/src/pipecat/services/deepgram/sagemaker/stt.py +++ b/src/pipecat/services/deepgram/sagemaker/stt.py @@ -14,7 +14,7 @@ languages, and various Deepgram features. import asyncio import json -from dataclasses import dataclass +from dataclasses import dataclass, fields from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -32,29 +32,20 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.aws.sagemaker.bidi_client import SageMakerBidiClient -from pipecat.services.deepgram.stt import DeepgramSTTSettings -from pipecat.services.settings import STTSettings +from pipecat.services.deepgram.stt import DeepgramSTTSettings, LiveOptions +from pipecat.services.settings import STTSettings, _warn_deprecated_param, is_given from pipecat.services.stt_latency import DEEPGRAM_SAGEMAKER_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_stt -try: - from pipecat.services.deepgram.stt import LiveOptions -except ModuleNotFoundError as e: - logger.error(f"Exception: {e}") - logger.error( - "In order to use DeepgramSageMakerSTTService, you need to `pip install pipecat-ai[deepgram,sagemaker]`." - ) - raise Exception(f"Missing module: {e}") - @dataclass class DeepgramSageMakerSTTSettings(DeepgramSTTSettings): """Settings for the Deepgram SageMaker STT service. - See ``DeepgramSTTSettings`` for full documentation. + Inherits all fields from :class:`DeepgramSTTSettings`. """ pass @@ -72,14 +63,13 @@ class DeepgramSageMakerSTTService(STTService): - AWS credentials configured (via environment variables, AWS CLI, or instance metadata) - A deployed SageMaker endpoint with Deepgram model: https://developers.deepgram.com/docs/deploy-amazon-sagemaker - - Deepgram SDK for LiveOptions configuration Example:: stt = DeepgramSageMakerSTTService( endpoint_name="my-deepgram-endpoint", region="us-east-2", - live_options=LiveOptions( + settings=DeepgramSageMakerSTTSettings( model="nova-3", language="en", interim_results=True, @@ -95,8 +85,13 @@ class DeepgramSageMakerSTTService(STTService): *, endpoint_name: str, region: str, + encoding: str = "linear16", + channels: int = 1, + multichannel: bool = False, sample_rate: Optional[int] = None, + mip_opt_out: Optional[bool] = None, live_options: Optional[LiveOptions] = None, + settings: Optional[DeepgramSageMakerSTTSettings] = None, ttfs_p99_latency: Optional[float] = DEEPGRAM_SAGEMAKER_TTFS_P99, **kwargs, ): @@ -106,48 +101,100 @@ class DeepgramSageMakerSTTService(STTService): endpoint_name: Name of the SageMaker endpoint with Deepgram model deployed (e.g., "my-deepgram-nova-3-endpoint"). region: AWS region where the endpoint is deployed (e.g., "us-east-2"). - sample_rate: Audio sample rate in Hz. If None, uses value from - live_options or defaults to the value from StartFrame. - live_options: Deepgram LiveOptions configuration. Treated as a - delta from a set of sensible defaults — only the fields you - set are overridden; all others keep their default values. + encoding: Audio encoding format. Defaults to "linear16". + channels: Number of audio channels. Defaults to 1. + multichannel: Transcribe each audio channel independently. + Defaults to False. + sample_rate: Audio sample rate in Hz. If None, uses the pipeline + sample rate. + mip_opt_out: Opt out of Deepgram model improvement program. + live_options: Legacy configuration options. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramSageMakerSTTSettings(...)`` for + runtime-updatable fields and direct init parameters for + connection-level config. + + settings: Runtime-updatable settings. When provided alongside + ``live_options``, ``settings`` values take precedence (applied + after the ``live_options`` merge). ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the parent STTService. """ - sample_rate = sample_rate or (live_options.sample_rate if live_options else None) - - settings = DeepgramSageMakerSTTSettings( + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepgramSageMakerSTTSettings( model="nova-3", language=Language.EN, - encoding="linear16", - channels=1, - interim_results=True, - smart_format=False, - punctuate=True, - profanity_filter=True, - vad_events=False, + detect_entities=False, diarize=False, + dictation=False, endpointing=None, + interim_results=True, + keyterm=None, + keywords=None, + numerals=False, + profanity_filter=True, + punctuate=True, + redact=None, + replace=None, + search=None, + smart_format=False, + utterance_end_ms=None, + vad_events=False, ) - if live_options: - lo_dict = live_options.to_dict() - delta = DeepgramSageMakerSTTSettings.from_mapping( - {k: v for k, v in lo_dict.items() if k != "sample_rate"} - ) - settings.apply_update(delta) + # 2. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", DeepgramSageMakerSTTSettings) + if not settings: + # Extract init-only fields from live_options + if live_options.sample_rate is not None and sample_rate is None: + sample_rate = live_options.sample_rate + if live_options.encoding is not None: + encoding = live_options.encoding + if live_options.channels is not None: + channels = live_options.channels + if live_options.multichannel is not None: + multichannel = live_options.multichannel + if live_options.mip_opt_out is not None: + mip_opt_out = live_options.mip_opt_out + + # Build settings delta from remaining fields + init_only = { + "sample_rate", + "encoding", + "channels", + "multichannel", + "mip_opt_out", + } + lo_dict = {k: v for k, v in live_options.to_dict().items() if k not in init_only} + delta = DeepgramSageMakerSTTSettings.from_mapping(lo_dict) + default_settings.apply_update(delta) + + # 3. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + # Sync extra to top-level fields so self._settings is unambiguous + default_settings._sync_extra_to_fields() super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) self._endpoint_name = endpoint_name self._region = region + # Init-only connection config (not runtime-updatable). + self._encoding = encoding + self._channels = channels + self._multichannel = multichannel + self._mip_opt_out = mip_opt_out + self._client: Optional[SageMakerBidiClient] = None self._response_task: Optional[asyncio.Task] = None self._keepalive_task: Optional[asyncio.Task] = None @@ -167,6 +214,10 @@ class DeepgramSageMakerSTTService(STTService): if not changed: return changed + # Sync extra to fields after the update so self._settings stays unambiguous + if isinstance(self._settings, DeepgramSTTSettings): + self._settings._sync_extra_to_fields() + # TODO: someday we could reconnect here to apply updated settings. # Code might look something like the below: # await self._disconnect() @@ -219,6 +270,43 @@ class DeepgramSageMakerSTTService(STTService): yield ErrorFrame(error=f"Unknown error occurred: {e}") yield None + def _build_query_string(self) -> str: + """Build query string from current settings and init-only connection config.""" + params = {} + s = self._settings + + # Declared Deepgram-specific fields from settings + for f in fields(s): + if f.name in ("model", "language", "extra") or f.name.startswith("_"): + continue + value = getattr(s, f.name) + if not is_given(value) or value is None: + continue + params[f.name] = str(value).lower() if isinstance(value, bool) else str(value) + + # model and language + if is_given(s.model) and s.model is not None: + params["model"] = str(s.model) + if is_given(s.language) and s.language is not None: + params["language"] = str(s.language) + + # Init-only connection config + params["encoding"] = self._encoding + params["channels"] = str(self._channels) + params["multichannel"] = str(self._multichannel).lower() + params["sample_rate"] = str(self.sample_rate) + + if self._mip_opt_out is not None: + params["mip_opt_out"] = str(self._mip_opt_out).lower() + + # Any remaining values in extra + if s.extra: + for key, value in s.extra.items(): + if value is not None: + params[key] = str(value).lower() if isinstance(value, bool) else str(value) + + return "&".join(f"{k}={v}" for k, v in params.items()) + async def _connect(self): """Connect to the SageMaker endpoint and start the BiDi session. @@ -228,21 +316,7 @@ class DeepgramSageMakerSTTService(STTService): """ logger.debug("Connecting to Deepgram on SageMaker...") - # Reconstruct a LiveOptions from the flat settings to build the query string. - live_options = LiveOptions(**self._settings.given_fields()) - - # Build query string from live_options, converting booleans to strings - query_params = {} - for key, value in live_options.to_dict().items(): - if value is not None: - # Convert boolean values to lowercase strings for Deepgram API - if isinstance(value, bool): - query_params[key] = str(value).lower() - else: - query_params[key] = str(value) - query_params["sample_rate"] = str(self.sample_rate) - - query_string = "&".join(f"{k}={v}" for k, v in query_params.items()) + query_string = self._build_query_string() # Create BiDi client self._client = SageMakerBidiClient( diff --git a/src/pipecat/services/deepgram/sagemaker/tts.py b/src/pipecat/services/deepgram/sagemaker/tts.py index b583ce76c..3693178a1 100644 --- a/src/pipecat/services/deepgram/sagemaker/tts.py +++ b/src/pipecat/services/deepgram/sagemaker/tts.py @@ -14,7 +14,7 @@ streaming audio output. import asyncio import json -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -33,20 +33,16 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.aws.sagemaker.bidi_client import SageMakerBidiClient -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @dataclass class DeepgramSageMakerTTSSettings(TTSSettings): - """Settings for Deepgram SageMaker TTS service. + """Settings for Deepgram SageMaker TTS service.""" - Parameters: - encoding: Audio encoding format (e.g. "linear16"). - """ - - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class DeepgramSageMakerTTSService(TTSService): @@ -78,9 +74,10 @@ class DeepgramSageMakerTTSService(TTSService): *, endpoint_name: str, region: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramSageMakerTTSSettings] = None, **kwargs, ): """Initialize the Deepgram SageMaker TTS service. @@ -90,26 +87,41 @@ class DeepgramSageMakerTTSService(TTSService): deployed (e.g., "my-deepgram-tts-endpoint"). region: AWS region where the endpoint is deployed (e.g., "us-east-2"). voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramSageMakerTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses the value from StartFrame. encoding: Audio encoding format. Defaults to "linear16". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ + if voice is not None: + _warn_deprecated_param("voice", DeepgramSageMakerTTSSettings, "voice") + + voice = voice or "aura-2-helena-en" + + default_settings = DeepgramSageMakerTTSSettings( + model=None, + voice=voice, + language=None, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, push_stop_frames=True, pause_frame_processing=True, append_trailing_space=True, - settings=DeepgramSageMakerTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) self._endpoint_name = endpoint_name self._region = region + self._encoding = encoding self._client: Optional[SageMakerBidiClient] = None self._response_task: Optional[asyncio.Task] = None @@ -175,8 +187,7 @@ class DeepgramSageMakerTTSService(TTSService): logger.debug("Connecting to Deepgram TTS on SageMaker...") query_string = ( - f"model={self._settings.voice}&encoding={self._settings.encoding}" - f"&sample_rate={self.sample_rate}" + f"model={self._settings.voice}&encoding={self._encoding}&sample_rate={self.sample_rate}" ) self._client = SageMakerBidiClient( diff --git a/src/pipecat/services/deepgram/stt.py b/src/pipecat/services/deepgram/stt.py index 343a87e2a..d377fe69a 100644 --- a/src/pipecat/services/deepgram/stt.py +++ b/src/pipecat/services/deepgram/stt.py @@ -8,7 +8,7 @@ import asyncio from dataclasses import dataclass, field, fields -from typing import Any, AsyncGenerator, Dict, Optional +from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -25,7 +25,13 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import _S, NOT_GIVEN, STTSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + STTSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.services.stt_latency import DEEPGRAM_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language @@ -50,8 +56,11 @@ class LiveOptions: """Deepgram live transcription options. Compatibility wrapper that mirrors the ``LiveOptions`` class removed in - deepgram-sdk v6. Pass this to :class:`DeepgramSTTService` via the - ``live_options`` constructor argument. + deepgram-sdk v6. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramSTTSettings(...)`` for runtime-updatable fields + and direct ``__init__`` parameters for connection-level config instead. """ def __init__( @@ -172,29 +181,42 @@ class DeepgramSTTSettings(STTSettings): ``model`` and ``language`` are inherited from ``STTSettings`` / ``ServiceSettings``. Additional Deepgram connection params may - be passed in through extra ``extra`` (also inherited). + be passed in through ``extra`` (also inherited). Parameters: - channels: Number of audio channels. + detect_entities: Enable named entity detection. diarize: Enable speaker diarization. - encoding: Audio encoding (e.g. ``"linear16"``). + dictation: Enable dictation mode (converts commands to punctuation). endpointing: Endpointing sensitivity in ms, or ``False`` to disable. interim_results: Whether to emit interim transcriptions. + keyterm: Keyterms to boost (str or list of str). + keywords: Keywords to boost (str or list of str). + numerals: Convert spoken numbers to numerals. profanity_filter: Filter profanity from transcripts. punctuate: Add punctuation to transcripts. + redact: Redact sensitive information (str or list of redaction types). + replace: Word replacement rules (str or list). + search: Search terms to highlight (str or list of str). smart_format: Apply smart formatting to transcripts. + utterance_end_ms: Silence duration in ms before an utterance-end event. vad_events: Enable Deepgram VAD speech-started / utterance-end events. - extra: Additional Deepgram query parameters not covered by the fields above. """ - channels: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + detect_entities: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) diarize: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + dictation: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) endpointing: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) interim_results: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + keyterm: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + keywords: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + numerals: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) profanity_filter: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) punctuate: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + redact: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + replace: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + search: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) smart_format: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + utterance_end_ms: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) vad_events: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) def _sync_extra_to_fields(self) -> None: @@ -252,10 +274,18 @@ class DeepgramSTTService(STTService): api_key: str, url: str = "", base_url: str = "", + encoding: str = "linear16", + channels: int = 1, + multichannel: bool = False, sample_rate: Optional[int] = None, + callback: Optional[str] = None, + callback_method: Optional[str] = None, + tag: Optional[Any] = None, + mip_opt_out: Optional[bool] = None, live_options: Optional[LiveOptions] = None, - addons: Optional[Dict] = None, + addons: Optional[dict] = None, should_interrupt: bool = True, + settings: Optional[DeepgramSTTSettings] = None, ttfs_p99_latency: Optional[float] = DEEPGRAM_TTFS_P99, **kwargs, ): @@ -269,16 +299,32 @@ class DeepgramSTTService(STTService): Parameter `url` is deprecated, use `base_url` instead. base_url: Custom Deepgram API base URL. - sample_rate: Audio sample rate. If None, uses default or live_options value. - live_options: :class: LiveOptions configuration. Treated as a - delta from a set of sensible defaults — only the fields you - set are overridden; all others keep their default values. + encoding: Audio encoding format. Defaults to "linear16". + channels: Number of audio channels. Defaults to 1. + multichannel: Transcribe each audio channel independently. + Defaults to False. + sample_rate: Audio sample rate in Hz. If None, uses the pipeline + sample rate. + callback: Callback URL for async transcription delivery. + callback_method: HTTP method for the callback (``"GET"`` or ``"POST"``). + tag: Custom billing tag. + mip_opt_out: Opt out of Deepgram model improvement program. + live_options: Legacy configuration options. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramSTTSettings(...)`` for runtime-updatable + fields and direct init parameters for connection-level config. + addons: Additional Deepgram features to enable. - should_interrupt: Determine whether the bot should be interrupted when Deepgram VAD events are enabled and the system detects that the user is speaking. + should_interrupt: Whether to interrupt the bot when Deepgram VAD + detects the user is speaking. .. deprecated:: 0.0.99 This parameter will be removed along with `vad_events` support. + settings: Runtime-updatable settings. When provided alongside + ``live_options``, ``settings`` values take precedence (applied + after the ``live_options`` merge). ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the parent STTService. @@ -286,8 +332,6 @@ class DeepgramSTTService(STTService): Note: The `vad_events` option in LiveOptions is deprecated as of version 0.0.99 and will be removed in a future version. Please use the Silero VAD instead. """ - sample_rate = sample_rate or (live_options.sample_rate if live_options else None) - if url: import warnings @@ -299,39 +343,88 @@ class DeepgramSTTService(STTService): ) base_url = url - settings = DeepgramSTTSettings( + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepgramSTTSettings( model="nova-3-general", language=Language.EN, - encoding="linear16", - channels=1, - interim_results=True, - smart_format=False, - punctuate=True, - profanity_filter=True, - vad_events=False, + detect_entities=False, diarize=False, + dictation=False, endpointing=None, + interim_results=True, + keyterm=None, + keywords=None, + numerals=False, + profanity_filter=True, + punctuate=True, + redact=None, + replace=None, + search=None, + smart_format=False, + utterance_end_ms=None, + vad_events=False, ) - if live_options: - lo_dict = live_options.to_dict() - delta = DeepgramSTTSettings.from_mapping( - {k: v for k, v in lo_dict.items() if k != "sample_rate"} - ) - settings.apply_update(delta) + # 2. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", DeepgramSTTSettings) + if not settings: + # Extract init-only fields from live_options + if live_options.sample_rate is not None and sample_rate is None: + sample_rate = live_options.sample_rate + if live_options.encoding is not None: + encoding = live_options.encoding + if live_options.channels is not None: + channels = live_options.channels + if live_options.callback is not None: + callback = live_options.callback + if live_options.callback_method is not None: + callback_method = live_options.callback_method + if live_options.tag is not None: + tag = live_options.tag + if live_options.mip_opt_out is not None: + mip_opt_out = live_options.mip_opt_out + if live_options.multichannel is not None: + multichannel = live_options.multichannel + + # Build settings delta from remaining fields + init_only = { + "sample_rate", + "encoding", + "channels", + "multichannel", + "callback", + "callback_method", + "tag", + "mip_opt_out", + } + lo_dict = {k: v for k, v in live_options.to_dict().items() if k not in init_only} + delta = DeepgramSTTSettings.from_mapping(lo_dict) + default_settings.apply_update(delta) + + # 3. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) # Sync extra to top-level fields so self._settings is unambiguous - settings._sync_extra_to_fields() + default_settings._sync_extra_to_fields() super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) self._addons = addons self._should_interrupt = should_interrupt + self._encoding = encoding + self._channels = channels + self._multichannel = multichannel + self._callback = callback + self._callback_method = callback_method + self._tag = tag + self._mip_opt_out = mip_opt_out if self._settings.vad_events: import warnings @@ -466,14 +559,26 @@ class DeepgramSTTService(STTService): if is_given(s.language) and s.language is not None: kwargs["language"] = str(s.language) + # Init-only connection config + kwargs["encoding"] = self._encoding + kwargs["channels"] = str(self._channels) + kwargs["multichannel"] = str(self._multichannel).lower() + kwargs["sample_rate"] = str(self.sample_rate) + + if self._callback is not None: + kwargs["callback"] = self._callback + if self._callback_method is not None: + kwargs["callback_method"] = self._callback_method + if self._tag is not None: + kwargs["tag"] = str(self._tag) + if self._mip_opt_out is not None: + kwargs["mip_opt_out"] = str(self._mip_opt_out).lower() + # Any remaining values in extra (that didn't map to declared fields) for key, value in s.extra.items(): if value is not None: kwargs[key] = str(value).lower() if isinstance(value, bool) else str(value) - # Always inject sample_rate from service level. - kwargs["sample_rate"] = str(self.sample_rate) - if self._addons: for key, value in self._addons.items(): kwargs[key] = str(value) diff --git a/src/pipecat/services/deepgram/tts.py b/src/pipecat/services/deepgram/tts.py index c05b90868..95db998e2 100644 --- a/src/pipecat/services/deepgram/tts.py +++ b/src/pipecat/services/deepgram/tts.py @@ -11,7 +11,7 @@ for generating speech from text using various voice models. """ import json -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional import aiohttp @@ -30,7 +30,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService, WebsocketTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -47,13 +47,9 @@ except ModuleNotFoundError as e: @dataclass class DeepgramTTSSettings(TTSSettings): - """Settings for Deepgram TTS service. + """Settings for Deepgram TTS service.""" - Parameters: - encoding: Audio encoding format (linear16, mulaw, alaw). - """ - - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class DeepgramTTSService(WebsocketTTSService): @@ -72,20 +68,27 @@ class DeepgramTTSService(WebsocketTTSService): self, *, api_key: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, base_url: str = "wss://api.deepgram.com", sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramTTSSettings] = None, **kwargs, ): """Initialize the Deepgram WebSocket TTS service. Args: api_key: Deepgram API key for authentication. - voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + voice: Voice model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramTTSSettings(voice=...)`` instead. + base_url: WebSocket base URL for Deepgram API. Defaults to "wss://api.deepgram.com". sample_rate: Audio sample rate in Hz. If None, uses service default. encoding: Audio encoding format. Defaults to "linear16". Must be one of SUPPORTED_ENCODINGS. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent InterruptibleTTSService class. Raises: @@ -96,22 +99,35 @@ class DeepgramTTSService(WebsocketTTSService): f"Unsupported encoding '{encoding}'. Must be one of {', '.join(self.SUPPORTED_ENCODINGS)} for WebSocket TTS." ) + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepgramTTSSettings( + model=None, + voice="aura-2-helena-en", + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice is not None: + _warn_deprecated_param("voice", DeepgramTTSSettings, "voice") + default_settings.model = voice + default_settings.voice = voice + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, pause_frame_processing=True, push_stop_frames=True, append_trailing_space=True, - settings=DeepgramTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._base_url = base_url + self._encoding = encoding self._receive_task = None self._context_id: Optional[str] = None @@ -216,7 +232,7 @@ class DeepgramTTSService(WebsocketTTSService): # Build WebSocket URL with query parameters params = [] params.append(f"model={self._settings.voice}") - params.append(f"encoding={self._settings.encoding}") + params.append(f"encoding={self._encoding}") params.append(f"sample_rate={self.sample_rate}") url = f"{self._base_url}/v1/speak?{'&'.join(params)}" @@ -375,38 +391,58 @@ class DeepgramHttpTTSService(TTSService): self, *, api_key: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, base_url: str = "https://api.deepgram.com", sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramTTSSettings] = None, **kwargs, ): """Initialize the Deepgram TTS service. Args: api_key: Deepgram API key for authentication. - voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + voice: Voice model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=DeepgramTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests with connection pooling. base_url: Custom base URL for Deepgram API. Defaults to "https://api.deepgram.com". sample_rate: Audio sample rate in Hz. If None, uses service default. encoding: Audio encoding format. Defaults to "linear16". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepgramTTSSettings( + model=None, + voice="aura-2-helena-en", + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice is not None: + _warn_deprecated_param("voice", DeepgramTTSSettings, "voice") + default_settings.model = voice + default_settings.voice = voice + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, - settings=DeepgramTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._session = aiohttp_session self._base_url = base_url + self._encoding = encoding def can_generate_metrics(self) -> bool: """Check if the service can generate metrics. @@ -436,7 +472,7 @@ class DeepgramHttpTTSService(TTSService): params = { "model": self._settings.voice, - "encoding": self._settings.encoding, + "encoding": self._encoding, "sample_rate": self.sample_rate, "container": "none", } diff --git a/src/pipecat/services/deepseek/llm.py b/src/pipecat/services/deepseek/llm.py index 70318c9ba..684e971ca 100644 --- a/src/pipecat/services/deepseek/llm.py +++ b/src/pipecat/services/deepseek/llm.py @@ -6,10 +6,22 @@ """DeepSeek LLM service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class DeepSeekLLMSettings(OpenAILLMSettings): + """Settings for DeepSeek LLM service.""" + + pass class DeepSeekLLMService(OpenAILLMService): @@ -19,12 +31,15 @@ class DeepSeekLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: DeepSeekLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.deepseek.com/v1", - model: str = "deepseek-chat", + model: Optional[str] = None, + settings: Optional[DeepSeekLLMSettings] = None, **kwargs, ): """Initialize the DeepSeek LLM service. @@ -33,9 +48,27 @@ class DeepSeekLLMService(OpenAILLMService): api_key: The API key for accessing DeepSeek's API. base_url: The base URL for DeepSeek API. Defaults to "https://api.deepseek.com/v1". model: The model identifier to use. Defaults to "deepseek-chat". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = DeepSeekLLMSettings(model="deepseek-chat") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", DeepSeekLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for DeepSeek API endpoint. diff --git a/src/pipecat/services/elevenlabs/stt.py b/src/pipecat/services/elevenlabs/stt.py index 0cf13121e..f9899f7f1 100644 --- a/src/pipecat/services/elevenlabs/stt.py +++ b/src/pipecat/services/elevenlabs/stt.py @@ -35,7 +35,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import ELEVENLABS_REALTIME_TTFS_P99, ELEVENLABS_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService, WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -182,7 +182,8 @@ class ElevenLabsSTTSettings(STTSettings): """Settings for the ElevenLabs file-based STT service. Parameters: - tag_audio_events: Whether to include audio event tags in transcription. + tag_audio_events: Whether to include audio events like (laughter), + (coughing) in the transcription. """ tag_audio_events: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -195,7 +196,6 @@ class ElevenLabsRealtimeSTTSettings(STTSettings): See ``ElevenLabsRealtimeSTTService.InputParams`` for detailed descriptions. Parameters: - commit_strategy: How to segment speech - manual (Pipecat VAD) or vad (ElevenLabs VAD). vad_silence_threshold_secs: Seconds of silence before VAD commits (0.3-3.0). vad_threshold: VAD sensitivity (0.1-0.9, lower is more sensitive). min_speech_duration_ms: Minimum speech duration for VAD (50-2000ms). @@ -205,7 +205,6 @@ class ElevenLabsRealtimeSTTSettings(STTSettings): include_language_detection: Whether to include language detection in transcripts. """ - commit_strategy: CommitStrategy | _NotGiven = field(default_factory=lambda: NOT_GIVEN) vad_silence_threshold_secs: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) vad_threshold: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) min_speech_duration_ms: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -228,6 +227,9 @@ class ElevenLabsSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for ElevenLabs STT API. + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. tag_audio_events: Whether to include audio events like (laughter), (coughing), in the transcription. @@ -242,9 +244,10 @@ class ElevenLabsSTTService(SegmentedSTTService): api_key: str, aiohttp_session: aiohttp.ClientSession, base_url: str = "https://api.elevenlabs.io", - model: str = "scribe_v2", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsSTTSettings] = None, ttfs_p99_latency: Optional[float] = ELEVENLABS_TTFS_P99, **kwargs, ): @@ -254,25 +257,53 @@ class ElevenLabsSTTService(SegmentedSTTService): api_key: ElevenLabs API key for authentication. aiohttp_session: aiohttp ClientSession for HTTP requests. base_url: Base URL for ElevenLabs API. - model: Model ID for transcription. Defaults to "scribe_v2". + model: Model ID for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsSTTSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the STT service. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - params = params or ElevenLabsSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = ElevenLabsSTTSettings( + model="scribe_v2", + language="eng", + tag_audio_events=True, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", ElevenLabsSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", ElevenLabsSTTSettings) + if not settings: + if params.language is not None: + default_settings.language = ( + self.language_to_service_language(params.language) or "eng" + ) + default_settings.tag_audio_events = params.tag_audio_events + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=ElevenLabsSTTSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "eng", - tag_audio_events=params.tag_audio_events, - ), + settings=default_settings, **kwargs, ) @@ -429,6 +460,9 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for ElevenLabs Realtime STT API. + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsRealtimeSTTSettings(...)`` instead. + Parameters: language_code: ISO-639-1 or ISO-639-3 language code. Leave None for auto-detection. commit_strategy: How to segment speech - manual (Pipecat VAD) or vad (ElevenLabs VAD). @@ -460,9 +494,11 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): *, api_key: str, base_url: str = "api.elevenlabs.io", - model: str = "scribe_v2_realtime", + commit_strategy: CommitStrategy = CommitStrategy.MANUAL, + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsRealtimeSTTSettings] = None, ttfs_p99_latency: Optional[float] = ELEVENLABS_REALTIME_TTFS_P99, **kwargs, ): @@ -471,32 +507,69 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): Args: api_key: ElevenLabs API key for authentication. base_url: Base URL for ElevenLabs WebSocket API. - model: Model ID for transcription. Defaults to "scribe_v2_realtime". + commit_strategy: How to segment speech — ``CommitStrategy.MANUAL`` + (Pipecat VAD) or ``CommitStrategy.VAD`` (ElevenLabs VAD). + Defaults to ``CommitStrategy.MANUAL``. + model: Model ID for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsRealtimeSTTSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the STT service. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsRealtimeSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to WebsocketSTTService. """ - params = params or ElevenLabsRealtimeSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = ElevenLabsRealtimeSTTSettings( + model="scribe_v2_realtime", + language=None, + vad_silence_threshold_secs=None, + vad_threshold=None, + min_speech_duration_ms=None, + min_silence_duration_ms=None, + include_timestamps=False, + enable_logging=False, + include_language_detection=False, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", ElevenLabsRealtimeSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", ElevenLabsRealtimeSTTSettings) + if not settings: + default_settings.language = params.language_code + if params.commit_strategy != CommitStrategy.MANUAL: + commit_strategy = params.commit_strategy + default_settings.vad_silence_threshold_secs = params.vad_silence_threshold_secs + default_settings.vad_threshold = params.vad_threshold + default_settings.min_speech_duration_ms = params.min_speech_duration_ms + default_settings.min_silence_duration_ms = params.min_silence_duration_ms + default_settings.include_timestamps = params.include_timestamps + default_settings.enable_logging = params.enable_logging + default_settings.include_language_detection = params.include_language_detection + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=10, keepalive_interval=5, - settings=ElevenLabsRealtimeSTTSettings( - model=model, - language=params.language_code, - commit_strategy=params.commit_strategy, - vad_silence_threshold_secs=params.vad_silence_threshold_secs, - vad_threshold=params.vad_threshold, - min_speech_duration_ms=params.min_speech_duration_ms, - min_silence_duration_ms=params.min_silence_duration_ms, - include_timestamps=params.include_timestamps, - enable_logging=params.enable_logging, - include_language_detection=params.include_language_detection, - ), + settings=default_settings, **kwargs, ) @@ -505,6 +578,9 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): self._audio_format = "" # initialized in start() self._receive_task = None + # Init-only config (not runtime-updatable). + self._commit_strategy = commit_strategy + self._connected_event = asyncio.Event() self._connected_event.set() @@ -581,7 +657,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): await self._start_metrics() elif isinstance(frame, VADUserStoppedSpeakingFrame): # Send commit when user stops speaking (manual commit mode) - if self._settings.commit_strategy == CommitStrategy.MANUAL: + if self._commit_strategy == CommitStrategy.MANUAL: if self._websocket and self._websocket.state is State.OPEN: try: commit_message = { @@ -684,7 +760,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): params.append(f"language_code={self._settings.language}") params.append(f"audio_format={self._audio_format}") - params.append(f"commit_strategy={self._settings.commit_strategy.value}") + params.append(f"commit_strategy={self._commit_strategy.value}") # Add optional parameters if self._settings.include_timestamps: @@ -701,7 +777,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): ) # Add VAD parameters if using VAD commit strategy and values are specified - if self._settings.commit_strategy == CommitStrategy.VAD: + if self._commit_strategy == CommitStrategy.VAD: if self._settings.vad_silence_threshold_secs is not None: params.append( f"vad_silence_threshold_secs={self._settings.vad_silence_threshold_secs}" @@ -861,7 +937,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): await self._handle_transcription(text, True, language) - finalized = self._settings.commit_strategy == CommitStrategy.MANUAL + finalized = self._commit_strategy == CommitStrategy.MANUAL await self.push_frame( TranscriptionFrame( @@ -905,7 +981,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): await self._handle_transcription(text, True, language) - finalized = self._settings.commit_strategy == CommitStrategy.MANUAL + finalized = self._commit_strategy == CommitStrategy.MANUAL # This message is sent after committed_transcript when include_timestamps=true. # It contains the full transcript data including text and word-level timestamps. diff --git a/src/pipecat/services/elevenlabs/tts.py b/src/pipecat/services/elevenlabs/tts.py index 1811ed971..cfb08eb6d 100644 --- a/src/pipecat/services/elevenlabs/tts.py +++ b/src/pipecat/services/elevenlabs/tts.py @@ -44,7 +44,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import ( AudioContextTTSService, TextAggregationMode, @@ -201,9 +201,6 @@ class ElevenLabsTTSSettings(TTSSettings): style: Style control for voice expression (0.0 to 1.0). use_speaker_boost: Whether to use speaker boost enhancement. speed: Voice speed control (0.7 to 1.2). - auto_mode: Whether to enable automatic mode optimization. - enable_ssml_parsing: Whether to parse SSML tags in text. - enable_logging: Whether to enable ElevenLabs logging. apply_text_normalization: Text normalization mode ("auto", "on", "off"). """ @@ -212,9 +209,6 @@ class ElevenLabsTTSSettings(TTSSettings): style: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) use_speaker_boost: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speed: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - auto_mode: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - enable_ssml_parsing: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - enable_logging: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) apply_text_normalization: Literal["auto", "on", "off"] | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) @@ -228,8 +222,6 @@ class ElevenLabsTTSSettings(TTSSettings): {"stability", "similarity_boost", "style", "use_speaker_boost", "speed"} ) - _aliases: ClassVar[Dict[str, str]] = {"voice_id": "voice"} - @dataclass class ElevenLabsHttpTTSSettings(TTSSettings): @@ -255,8 +247,6 @@ class ElevenLabsHttpTTSSettings(TTSSettings): default_factory=lambda: NOT_GIVEN ) - _aliases: ClassVar[Dict[str, str]] = {"voice_id": "voice"} - def calculate_word_times( alignment_info: Mapping[str, Any], @@ -331,6 +321,9 @@ class ElevenLabsTTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for ElevenLabs TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsTTSSettings(...)`` instead. + Parameters: language: Language to use for synthesis. stability: Voice stability control (0.0 to 1.0). @@ -361,11 +354,13 @@ class ElevenLabsTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, - model: str = "eleven_turbo_v2_5", + voice_id: Optional[str] = None, + model: Optional[str] = None, url: str = "wss://api.elevenlabs.io", sample_rate: Optional[int] = None, + pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsTTSSettings] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, **kwargs, @@ -375,10 +370,26 @@ class ElevenLabsTTSService(AudioContextTTSService): Args: api_key: ElevenLabs API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsTTSSettings(voice=...)`` instead. + model: TTS model to use (e.g., "eleven_turbo_v2_5"). + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsTTSSettings(model=...)`` instead. + url: WebSocket URL for ElevenLabs TTS API. sample_rate: Audio sample rate. If None, uses default. + pronunciation_dictionary_locators: List of pronunciation dictionary + locators to use. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregation_mode: How to aggregate incoming text before synthesis. aggregate_sentences: Whether to aggregate sentences within the TTSService. @@ -403,7 +414,64 @@ class ElevenLabsTTSService(AudioContextTTSService): # Finally, ElevenLabs doesn't provide information on when the bot stops # speaking for a while, so we want the parent class to send TTSStopFrame # after a short period not receiving any audio. - params = params or ElevenLabsTTSService.InputParams() + + # 1. Initialize default_settings with hardcoded defaults + default_settings = ElevenLabsTTSSettings( + model="eleven_turbo_v2_5", + voice=None, + language=None, + stability=None, + similarity_boost=None, + style=None, + use_speaker_boost=None, + speed=None, + apply_text_normalization=None, + ) + + # Track init-only URL params through the override chain + _auto_mode = True + _enable_ssml_parsing = None + _enable_logging = None + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", ElevenLabsTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", ElevenLabsTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + _pronunciation_dictionary_locators = pronunciation_dictionary_locators + if params is not None: + _warn_deprecated_param("params", ElevenLabsTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.stability is not None: + default_settings.stability = params.stability + if params.similarity_boost is not None: + default_settings.similarity_boost = params.similarity_boost + if params.style is not None: + default_settings.style = params.style + if params.use_speaker_boost is not None: + default_settings.use_speaker_boost = params.use_speaker_boost + if params.speed is not None: + default_settings.speed = params.speed + if params.auto_mode is not None: + _auto_mode = str(params.auto_mode).lower() + if params.enable_ssml_parsing is not None: + _enable_ssml_parsing = params.enable_ssml_parsing + if params.enable_logging is not None: + _enable_logging = params.enable_logging + if params.apply_text_normalization is not None: + default_settings.apply_text_normalization = params.apply_text_normalization + if _pronunciation_dictionary_locators is None: + _pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -413,31 +481,21 @@ class ElevenLabsTTSService(AudioContextTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=ElevenLabsTTSSettings( - model=model, - voice=voice_id, - language=( - self.language_to_service_language(params.language) if params.language else None - ), - stability=params.stability, - similarity_boost=params.similarity_boost, - style=params.style, - use_speaker_boost=params.use_speaker_boost, - speed=params.speed, - auto_mode=str(params.auto_mode).lower(), - enable_ssml_parsing=params.enable_ssml_parsing, - enable_logging=params.enable_logging, - apply_text_normalization=params.apply_text_normalization, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._url = url + # Init-only WebSocket URL params (not runtime-updatable). + self._auto_mode = _auto_mode + self._enable_ssml_parsing = _enable_ssml_parsing + self._enable_logging = _enable_logging + self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + self._pronunciation_dictionary_locators = _pronunciation_dictionary_locators self._cumulative_time = 0 # Track partial words that span across alignment chunks @@ -468,20 +526,7 @@ class ElevenLabsTTSService(AudioContextTTSService): return language_to_elevenlabs_language(language) def _set_voice_settings(self): - ts = self._settings - voice_setting_keys = [ - "stability", - "similarity_boost", - "style", - "use_speaker_boost", - "speed", - ] - voice_settings = {} - for key in voice_setting_keys: - val = getattr(ts, key, None) - if val is not None: - voice_settings[key] = val - return voice_settings or None + return build_elevenlabs_voice_settings(self._settings) async def _update_settings(self, delta: TTSSettings) -> dict[str, Any]: """Apply a settings delta, reconnecting as needed. @@ -620,13 +665,13 @@ class ElevenLabsTTSService(AudioContextTTSService): voice_id = self._settings.voice model = self._settings.model output_format = self._output_format - url = f"{self._url}/v1/text-to-speech/{voice_id}/multi-stream-input?model_id={model}&output_format={output_format}&auto_mode={self._settings.auto_mode}" + url = f"{self._url}/v1/text-to-speech/{voice_id}/multi-stream-input?model_id={model}&output_format={output_format}&auto_mode={self._auto_mode}" - if self._settings.enable_ssml_parsing: - url += f"&enable_ssml_parsing={self._settings.enable_ssml_parsing}" + if self._enable_ssml_parsing: + url += f"&enable_ssml_parsing={self._enable_ssml_parsing}" - if self._settings.enable_logging: - url += f"&enable_logging={self._settings.enable_logging}" + if self._enable_logging: + url += f"&enable_logging={self._enable_logging}" if self._settings.apply_text_normalization is not None: url += f"&apply_text_normalization={self._settings.apply_text_normalization}" @@ -871,6 +916,9 @@ class ElevenLabsHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for ElevenLabs HTTP TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsHttpTTSSettings(...)`` instead. + Parameters: language: Language to use for synthesis. optimize_streaming_latency: Latency optimization level (0-4). @@ -897,12 +945,14 @@ class ElevenLabsHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "eleven_turbo_v2_5", + model: Optional[str] = None, base_url: str = "https://api.elevenlabs.io", sample_rate: Optional[int] = None, + pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsHttpTTSSettings] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, **kwargs, @@ -912,11 +962,27 @@ class ElevenLabsHttpTTSService(TTSService): Args: api_key: ElevenLabs API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsHttpTTSSettings(voice=...)`` instead. + aiohttp_session: aiohttp ClientSession for HTTP requests. model: TTS model to use (e.g., "eleven_turbo_v2_5"). + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsHttpTTSSettings(model=...)`` instead. + base_url: Base URL for ElevenLabs HTTP API. sample_rate: Audio sample rate. If None, uses default. + pronunciation_dictionary_locators: List of pronunciation dictionary + locators to use. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=ElevenLabsHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregation_mode: How to aggregate incoming text before synthesis. aggregate_sentences: Whether to aggregate sentences within the TTSService. @@ -925,7 +991,55 @@ class ElevenLabsHttpTTSService(TTSService): **kwargs: Additional arguments passed to the parent service. """ - params = params or ElevenLabsHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = ElevenLabsHttpTTSSettings( + model="eleven_turbo_v2_5", + voice=None, + language=None, + optimize_streaming_latency=None, + stability=None, + similarity_boost=None, + style=None, + use_speaker_boost=None, + speed=None, + apply_text_normalization=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", ElevenLabsHttpTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", ElevenLabsHttpTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + _pronunciation_dictionary_locators = pronunciation_dictionary_locators + if params is not None: + _warn_deprecated_param("params", ElevenLabsHttpTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.optimize_streaming_latency is not None: + default_settings.optimize_streaming_latency = params.optimize_streaming_latency + if params.stability is not None: + default_settings.stability = params.stability + if params.similarity_boost is not None: + default_settings.similarity_boost = params.similarity_boost + if params.style is not None: + default_settings.style = params.style + if params.use_speaker_boost is not None: + default_settings.use_speaker_boost = params.use_speaker_boost + if params.speed is not None: + default_settings.speed = params.speed + if params.apply_text_normalization is not None: + default_settings.apply_text_normalization = params.apply_text_normalization + if _pronunciation_dictionary_locators is None: + _pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -934,20 +1048,7 @@ class ElevenLabsHttpTTSService(TTSService): push_stop_frames=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=ElevenLabsHttpTTSSettings( - model=model, - voice=voice_id, - language=self.language_to_service_language(params.language) - if params.language - else None, - optimize_streaming_latency=params.optimize_streaming_latency, - stability=params.stability, - similarity_boost=params.similarity_boost, - style=params.style, - use_speaker_boost=params.use_speaker_boost, - speed=params.speed, - apply_text_normalization=params.apply_text_normalization, - ), + settings=default_settings, **kwargs, ) @@ -957,7 +1058,7 @@ class ElevenLabsHttpTTSService(TTSService): self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + self._pronunciation_dictionary_locators = _pronunciation_dictionary_locators # Track cumulative time to properly sequence word timestamps across utterances self._cumulative_time = 0 diff --git a/src/pipecat/services/fal/image.py b/src/pipecat/services/fal/image.py index 3de48a984..c6fb81003 100644 --- a/src/pipecat/services/fal/image.py +++ b/src/pipecat/services/fal/image.py @@ -13,8 +13,8 @@ for creating images from text prompts using various AI models. import asyncio import io import os -from dataclasses import dataclass -from typing import AsyncGenerator, Dict, Optional, Union +from dataclasses import dataclass, field +from typing import Any, AsyncGenerator, Dict, Optional, Union import aiohttp from loguru import logger @@ -23,7 +23,7 @@ from pydantic import BaseModel from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import NOT_GIVEN, ImageGenSettings, _NotGiven, _warn_deprecated_param @dataclass @@ -32,8 +32,36 @@ class FalImageGenSettings(ImageGenSettings): Parameters: model: Fal.ai model identifier. + seed: Random seed for reproducible generation. ``None`` uses a random seed. + num_inference_steps: Number of inference steps for generation. + num_images: Number of images to generate. + image_size: Image dimensions as a string preset or dict with width/height. + expand_prompt: Whether to automatically expand/enhance the prompt. + enable_safety_checker: Whether to enable content safety filtering. + format: Output image format. """ + seed: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + num_inference_steps: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + num_images: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + image_size: str | Dict[str, int] | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + expand_prompt: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + enable_safety_checker: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + + def to_api_arguments(self) -> Dict[str, Any]: + """Build the Fal API arguments dict from settings, excluding None values.""" + args: Dict[str, Any] = {} + if self.seed is not None: + args["seed"] = self.seed + args["num_inference_steps"] = self.num_inference_steps + args["num_images"] = self.num_images + args["image_size"] = self.image_size + args["expand_prompt"] = self.expand_prompt + args["enable_safety_checker"] = self.enable_safety_checker + args["format"] = self.format + return args + class FalImageGenService(ImageGenService): """Fal's image generation service. @@ -45,6 +73,9 @@ class FalImageGenService(ImageGenService): class InputParams(BaseModel): """Input parameters for Fal.ai image generation. + .. deprecated:: 0.0.105 + Use ``settings=FalImageGenSettings(...)`` instead. + Parameters: seed: Random seed for reproducible generation. If None, uses random seed. num_inference_steps: Number of inference steps for generation. Defaults to 8. @@ -63,26 +94,70 @@ class FalImageGenService(ImageGenService): enable_safety_checker: bool = True format: str = "png" + _settings: FalImageGenSettings + def __init__( self, *, - params: InputParams, + params: Optional[InputParams] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "fal-ai/fast-sdxl", + model: Optional[str] = None, key: Optional[str] = None, + settings: Optional[FalImageGenSettings] = None, **kwargs, ): """Initialize the FalImageGenService. Args: params: Input parameters for image generation configuration. + + .. deprecated:: 0.0.105 + Use ``settings=FalImageGenSettings(...)`` instead. + aiohttp_session: HTTP client session for downloading generated images. model: The Fal.ai model to use for generation. Defaults to "fal-ai/fast-sdxl". + + .. deprecated:: 0.0.105 + Use ``settings=FalImageGenSettings(model=...)`` instead. + key: Optional API key for Fal.ai. If provided, sets FAL_KEY environment variable. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent ImageGenService. """ - super().__init__(settings=FalImageGenSettings(model=model), **kwargs) - self._params = params + # 1. Initialize default_settings with hardcoded defaults + default_settings = FalImageGenSettings( + model="fal-ai/fast-sdxl", + seed=None, + num_inference_steps=8, + num_images=1, + image_size="square_hd", + expand_prompt=False, + enable_safety_checker=True, + format="png", + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", FalImageGenSettings, "model") + default_settings.model = model + + if params is not None: + _warn_deprecated_param("params", FalImageGenSettings) + if not settings: + default_settings.seed = params.seed + default_settings.num_inference_steps = params.num_inference_steps + default_settings.num_images = params.num_images + default_settings.image_size = params.image_size + default_settings.expand_prompt = params.expand_prompt + default_settings.enable_safety_checker = params.enable_safety_checker + default_settings.format = params.format + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._aiohttp_session = aiohttp_session self._api_key = key or os.getenv("FAL_KEY", "") if key: @@ -110,7 +185,7 @@ class FalImageGenService(ImageGenService): "Authorization": f"Key {self._api_key}", "Content-Type": "application/json", } - payload = {"prompt": prompt, **self._params.model_dump(exclude_none=True)} + payload = {"prompt": prompt, **self._settings.to_api_arguments()} async with self._aiohttp_session.post( f"https://fal.run/{self._settings.model}", diff --git a/src/pipecat/services/fal/stt.py b/src/pipecat/services/fal/stt.py index 8a82904d7..18b8ed85c 100644 --- a/src/pipecat/services/fal/stt.py +++ b/src/pipecat/services/fal/stt.py @@ -12,7 +12,7 @@ transcription using segmented audio processing. import base64 import os -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import AsyncGenerator, Optional import aiohttp @@ -20,7 +20,7 @@ from loguru import logger from pydantic import BaseModel from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import STTSettings, _warn_deprecated_param from pipecat.services.stt_latency import FAL_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -143,18 +143,9 @@ def language_to_fal_language(language: Language) -> Optional[str]: @dataclass class FalSTTSettings(STTSettings): - """Settings for the Fal Wizper STT service. + """Settings for the Fal Wizper STT service.""" - Parameters: - task: Task to perform ('transcribe' or 'translate'). Defaults to - 'transcribe'. - chunk_level: Level of chunking ('segment'). Defaults to 'segment'. - version: Version of Wizper model to use. Defaults to '3'. - """ - - task: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - chunk_level: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - version: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class FalSTTService(SegmentedSTTService): @@ -169,6 +160,9 @@ class FalSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for Fal's Wizper API. + .. deprecated:: 0.0.105 + Use ``settings=FalSTTSettings(...)`` instead. + Parameters: language: Language of the audio input. Defaults to English. task: Task to perform ('transcribe' or 'translate'). Defaults to 'transcribe'. @@ -186,8 +180,12 @@ class FalSTTService(SegmentedSTTService): *, api_key: Optional[str] = None, aiohttp_session: Optional[aiohttp.ClientSession] = None, + task: str = "transcribe", + chunk_level: str = "segment", + version: str = "3", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[FalSTTSettings] = None, ttfs_p99_latency: Optional[float] = FAL_TTFS_P99, **kwargs, ): @@ -197,29 +195,60 @@ class FalSTTService(SegmentedSTTService): api_key: Fal API key. If not provided, will check FAL_KEY environment variable. aiohttp_session: Optional aiohttp ClientSession for HTTP requests. If not provided, a session will be created and managed internally. + task: Task to perform (``"transcribe"`` or ``"translate"``). + Defaults to ``"transcribe"``. + chunk_level: Level of chunking (``"segment"``). Defaults to ``"segment"``. + version: Version of Wizper model to use. Defaults to ``"3"``. sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the Wizper API. + + .. deprecated:: 0.0.105 + Use ``settings=FalSTTSettings(...)`` for model/language and + direct init parameters for task/chunk_level/version instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - params = params or FalSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = FalSTTSettings( + model=None, + language=language_to_fal_language(Language.EN) or "en", + ) + + # 2. (no deprecated direct args for this service) + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", FalSTTSettings) + if not settings: + default_settings.language = ( + language_to_fal_language(params.language) if params.language else "en" + ) + if params.task != "transcribe": + task = params.task + if params.chunk_level != "segment": + chunk_level = params.chunk_level + if params.version != "3": + version = params.version + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=FalSTTSettings( - model=None, - language=self.language_to_service_language(params.language) - if params.language - else "en", - task=params.task, - chunk_level=params.chunk_level, - version=params.version, - ), + settings=default_settings, **kwargs, ) + self._task = task + self._chunk_level = chunk_level + self._version = version + self._api_key = api_key or os.getenv("FAL_KEY", "") if not self._api_key: raise ValueError( @@ -275,7 +304,15 @@ class FalSTTService(SegmentedSTTService): self._session = aiohttp.ClientSession() data_uri = f"data:audio/x-wav;base64,{base64.b64encode(audio).decode()}" - payload = {"audio_url": data_uri, **self._settings.given_fields()} + payload: dict = {"audio_url": data_uri} + if self._settings.language is not None: + payload["language"] = self._settings.language + if self._task is not None: + payload["task"] = self._task + if self._chunk_level is not None: + payload["chunk_level"] = self._chunk_level + if self._version is not None: + payload["version"] = self._version headers = { "Authorization": f"Key {self._api_key}", "Content-Type": "application/json", diff --git a/src/pipecat/services/fireworks/llm.py b/src/pipecat/services/fireworks/llm.py index 92deb00b9..ccc9107f6 100644 --- a/src/pipecat/services/fireworks/llm.py +++ b/src/pipecat/services/fireworks/llm.py @@ -6,10 +6,22 @@ """Fireworks AI service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class FireworksLLMSettings(OpenAILLMSettings): + """Settings for Fireworks LLM service.""" + + pass class FireworksLLMService(OpenAILLMService): @@ -19,12 +31,15 @@ class FireworksLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: FireworksLLMSettings + def __init__( self, *, api_key: str, - model: str = "accounts/fireworks/models/firefunction-v2", + model: Optional[str] = None, base_url: str = "https://api.fireworks.ai/inference/v1", + settings: Optional[FireworksLLMSettings] = None, **kwargs, ): """Initialize the Fireworks LLM service. @@ -32,10 +47,28 @@ class FireworksLLMService(OpenAILLMService): Args: api_key: The API key for accessing Fireworks AI. model: The model identifier to use. Defaults to "accounts/fireworks/models/firefunction-v2". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for Fireworks API. Defaults to "https://api.fireworks.ai/inference/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = FireworksLLMSettings(model="accounts/fireworks/models/firefunction-v2") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", FireworksLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Fireworks API endpoint. @@ -79,4 +112,12 @@ class FireworksLLMService(OpenAILLMService): params.update(params_from_context) params.update(self._settings.extra) + + # Prepend system instruction if set + if self._settings.system_instruction: + messages = params.get("messages", []) + params["messages"] = [ + {"role": "system", "content": self._settings.system_instruction} + ] + messages + return params diff --git a/src/pipecat/services/fish/tts.py b/src/pipecat/services/fish/tts.py index 9f9d753de..9ea749546 100644 --- a/src/pipecat/services/fish/tts.py +++ b/src/pipecat/services/fish/tts.py @@ -12,7 +12,7 @@ for streaming text-to-speech synthesis with customizable voice parameters. import uuid from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, ClassVar, Dict, Literal, Mapping, Optional +from typing import Any, AsyncGenerator, ClassVar, Dict, Literal, Mapping, Optional, Self from loguru import logger from pydantic import BaseModel @@ -29,7 +29,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -52,27 +52,21 @@ class FishAudioTTSSettings(TTSSettings): """Settings for Fish Audio TTS service. Parameters: - fish_sample_rate: Audio sample rate sent to the API. latency: Latency mode ("normal" or "balanced"). Defaults to "normal". - format: Audio output format. normalize: Whether to normalize audio output. Defaults to True. prosody_speed: Speech speed multiplier (0.5-2.0). Defaults to 1.0. prosody_volume: Volume adjustment in dB. Defaults to 0. reference_id: Reference ID of the voice model. """ - fish_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) latency: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) normalize: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) prosody_speed: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) prosody_volume: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) reference_id: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - _aliases: ClassVar[Dict[str, str]] = {"voice_id": "voice", "sample_rate": "fish_sample_rate"} - @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "FishAudioTTSSettings": + def from_mapping(cls, settings: Mapping[str, Any]) -> Self: """Construct settings from a plain dict, destructuring legacy nested ``prosody``.""" flat = dict(settings) nested = flat.pop("prosody", None) @@ -95,6 +89,9 @@ class FishAudioTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Input parameters for Fish Audio TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=FishAudioTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. latency: Latency mode ("normal" or "balanced"). Defaults to "normal". @@ -115,10 +112,11 @@ class FishAudioTTSService(InterruptibleTTSService): api_key: str, reference_id: Optional[str] = None, # This is the voice ID model: Optional[str] = None, # Deprecated - model_id: str = "s1", + model_id: Optional[str] = None, output_format: FishAudioOutputFormat = "pcm", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[FishAudioTTSSettings] = None, **kwargs, ): """Initialize the Fish Audio TTS service. @@ -126,29 +124,38 @@ class FishAudioTTSService(InterruptibleTTSService): Args: api_key: Fish Audio API key for authentication. reference_id: Reference ID of the voice model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=FishAudioTTSSettings(voice=...)`` instead. + model: Deprecated. Reference ID of the voice model to use for synthesis. - .. deprecated:: 0.0.74 - The `model` parameter is deprecated and will be removed in version 0.1.0. - Use `reference_id` instead to specify the voice model. + .. deprecated:: 0.0.74 + The ``model`` parameter is deprecated and will be removed in version 0.1.0. + Use ``reference_id`` instead to specify the voice model. + + model_id: Specify which Fish Audio TTS model to use (e.g. "s1"). + + .. deprecated:: 0.0.105 + Use ``settings=FishAudioTTSSettings(model=...)`` instead. - model_id: Specify which Fish Audio TTS model to use (e.g. "s1") output_format: Audio output format. Defaults to "pcm". sample_rate: Audio sample rate. If None, uses default. params: Additional input parameters for voice customization. + + .. deprecated:: 0.0.105 + Use ``settings=FishAudioTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ - params = params or FishAudioTTSService.InputParams() - # Validation for model and reference_id parameters if model and reference_id: raise ValueError( "Cannot specify both 'model' and 'reference_id'. Use 'reference_id' only." ) - if model is None and reference_id is None: - raise ValueError("Must specify 'reference_id' (or deprecated 'model') parameter.") - if model: import warnings @@ -162,21 +169,49 @@ class FishAudioTTSService(InterruptibleTTSService): ) reference_id = model + # 1. Initialize default_settings with hardcoded defaults + default_settings = FishAudioTTSSettings( + model="s1", + voice=None, + language=None, + latency="normal", + normalize=True, + prosody_speed=1.0, + prosody_volume=0, + reference_id=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if reference_id is not None: + _warn_deprecated_param("reference_id", FishAudioTTSSettings, "voice") + default_settings.voice = reference_id + default_settings.reference_id = reference_id + if model_id is not None: + _warn_deprecated_param("model_id", FishAudioTTSSettings, "model") + default_settings.model = model_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", FishAudioTTSSettings) + if not settings: + if params.latency is not None: + default_settings.latency = params.latency + if params.normalize is not None: + default_settings.normalize = params.normalize + if params.prosody_speed is not None: + default_settings.prosody_speed = params.prosody_speed + if params.prosody_volume is not None: + default_settings.prosody_volume = params.prosody_volume + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( push_stop_frames=True, pause_frame_processing=True, sample_rate=sample_rate, - settings=FishAudioTTSSettings( - model=model_id, - voice=reference_id, - fish_sample_rate=0, - latency=params.latency, - format=output_format, - normalize=params.normalize, - prosody_speed=params.prosody_speed, - prosody_volume=params.prosody_volume, - reference_id=reference_id, - ), + settings=default_settings, **kwargs, ) @@ -186,6 +221,10 @@ class FishAudioTTSService(InterruptibleTTSService): self._receive_task = None self._request_id = None + # Init-only audio format config (not runtime-updatable). + self._fish_sample_rate = 0 # Set in start() + self._output_format = output_format + def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -220,7 +259,7 @@ class FishAudioTTSService(InterruptibleTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.fish_sample_rate = self.sample_rate + self._fish_sample_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -270,9 +309,9 @@ class FishAudioTTSService(InterruptibleTTSService): # Send initial start message with ormsgpack request_settings = { - "sample_rate": self._settings.fish_sample_rate, + "sample_rate": self._fish_sample_rate, "latency": self._settings.latency, - "format": self._settings.format, + "format": self._output_format, "normalize": self._settings.normalize, "prosody": { "speed": self._settings.prosody_speed, diff --git a/src/pipecat/services/gladia/config.py b/src/pipecat/services/gladia/config.py index 5fd5bfdac..ec8997d7c 100644 --- a/src/pipecat/services/gladia/config.py +++ b/src/pipecat/services/gladia/config.py @@ -152,6 +152,10 @@ class MessagesConfig(BaseModel): class GladiaInputParams(BaseModel): """Configuration parameters for the Gladia STT service. + .. deprecated:: 0.0.105 + Use ``settings=GladiaSTTSettings(...)`` for runtime-updatable + fields and direct init parameters for encoding/bit_depth/channels. + Parameters: encoding: Audio encoding format bit_depth: Audio bit depth diff --git a/src/pipecat/services/gladia/stt.py b/src/pipecat/services/gladia/stt.py index bba554b4a..f1eca2dc2 100644 --- a/src/pipecat/services/gladia/stt.py +++ b/src/pipecat/services/gladia/stt.py @@ -15,7 +15,7 @@ import base64 import json import warnings from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, Dict, Literal, Optional +from typing import Any, AsyncGenerator, Literal, Optional import aiohttp from loguru import logger @@ -39,7 +39,7 @@ from pipecat.services.gladia.config import ( PreProcessingConfig, RealtimeProcessingConfig, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import GLADIA_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -191,28 +191,22 @@ class GladiaSTTSettings(STTSettings): """Settings for Gladia STT service. Parameters: - encoding: Audio encoding format. - bit_depth: Audio bit depth. - channels: Number of audio channels. + language_config: Language detection and handling configuration. custom_metadata: Additional metadata to include with requests. endpointing: Silence duration in seconds to mark end of speech. maximum_duration_without_endpointing: Maximum utterance duration without silence. - language_config: Detailed language configuration. pre_processing: Audio pre-processing options. realtime_processing: Real-time processing features. messages_config: WebSocket message filtering options. enable_vad: Enable VAD to trigger end of utterance detection. """ - encoding: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - bit_depth: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - channels: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - custom_metadata: Dict[str, Any] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + language_config: LanguageConfig | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + custom_metadata: dict[str, Any] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) endpointing: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) maximum_duration_without_endpointing: int | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) - language_config: LanguageConfig | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) pre_processing: PreProcessingConfig | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) @@ -247,12 +241,16 @@ class GladiaSTTService(WebsocketSTTService): api_key: str, region: Literal["us-west", "eu-west"] | None = None, url: str = "https://api.gladia.io/v2/live", + encoding: str = "wav/pcm", + bit_depth: int = 16, + channels: int = 1, confidence: Optional[float] = None, sample_rate: Optional[int] = None, - model: str = "solaria-1", + model: Optional[str] = None, params: Optional[GladiaInputParams] = None, max_buffer_size: int = 1024 * 1024 * 20, # 20MB default buffer should_interrupt: bool = True, + settings: Optional[GladiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = GLADIA_TTFS_P99, **kwargs, ): @@ -262,6 +260,9 @@ class GladiaSTTService(WebsocketSTTService): api_key: Gladia API key for authentication. region: Region used to process audio. eu-west or us-west. Defaults to eu-west. url: Gladia API URL. Defaults to "https://api.gladia.io/v2/live". + encoding: Audio encoding format. Defaults to ``"wav/pcm"``. + bit_depth: Audio bit depth. Defaults to 16. + channels: Number of audio channels. Defaults to 1. confidence: Minimum confidence threshold for transcriptions (0.0-1.0). .. deprecated:: 0.0.86 @@ -269,27 +270,26 @@ class GladiaSTTService(WebsocketSTTService): No confidence threshold is applied. sample_rate: Audio sample rate in Hz. If None, uses service default. - model: Model to use for transcription. Defaults to "solaria-1". + model: Model to use for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=GladiaSTTSettings(model=...)`` instead. + params: Additional configuration parameters for Gladia service. + + .. deprecated:: 0.0.105 + Use ``settings=GladiaSTTSettings(...)`` for runtime-updatable + fields and direct init parameters for encoding/bit_depth/channels. + max_buffer_size: Maximum size of audio buffer in bytes. Defaults to 20MB. should_interrupt: Determine whether the bot should be interrupted when Gladia VAD detects user speech. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService parent class. """ - params = params or GladiaInputParams() - - if params.language is not None: - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "The 'language' parameter is deprecated and will be removed in a future version. " - "Use 'language_config' instead.", - DeprecationWarning, - stacklevel=2, - ) - if confidence: with warnings.catch_warnings(): warnings.simplefilter("always") @@ -300,33 +300,74 @@ class GladiaSTTService(WebsocketSTTService): stacklevel=2, ) - # Resolve deprecated language → language_config at init time - language_config = params.language_config - if not language_config and params.language: - language_code = self.language_to_service_language(params.language) - if language_code: - language_config = LanguageConfig(languages=[language_code], code_switching=False) + # 1. Initialize default_settings with hardcoded defaults + default_settings = GladiaSTTSettings( + model="solaria-1", + language=None, + language_config=None, + custom_metadata=None, + endpointing=None, + maximum_duration_without_endpointing=5, + pre_processing=None, + realtime_processing=None, + messages_config=None, + enable_vad=False, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GladiaSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GladiaSTTSettings) + if params.language is not None: + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn( + "The 'language' parameter is deprecated and will be removed in a future " + "version. Use 'language_config' instead.", + DeprecationWarning, + stacklevel=2, + ) + if not settings: + # Extract init-only fields from params + if params.encoding is not None: + encoding = params.encoding + if params.bit_depth is not None: + bit_depth = params.bit_depth + if params.channels is not None: + channels = params.channels + default_settings.custom_metadata = params.custom_metadata + default_settings.endpointing = params.endpointing + default_settings.maximum_duration_without_endpointing = ( + params.maximum_duration_without_endpointing + ) + default_settings.pre_processing = params.pre_processing + default_settings.realtime_processing = params.realtime_processing + default_settings.messages_config = params.messages_config + default_settings.enable_vad = params.enable_vad + # Resolve deprecated language → language_config at init time + if params.language_config: + default_settings.language_config = params.language_config + elif params.language: + language_code = self.language_to_service_language(params.language) + if language_code: + default_settings.language_config = LanguageConfig( + languages=[language_code], code_switching=False + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=20, keepalive_interval=5, - settings=GladiaSTTSettings( - model=model, - language=None, - encoding=params.encoding, - bit_depth=params.bit_depth, - channels=params.channels, - custom_metadata=params.custom_metadata, - endpointing=params.endpointing, - maximum_duration_without_endpointing=params.maximum_duration_without_endpointing, - language_config=language_config, - pre_processing=params.pre_processing, - realtime_processing=params.realtime_processing, - messages_config=params.messages_config, - enable_vad=params.enable_vad, - ), + settings=default_settings, **kwargs, ) @@ -335,6 +376,11 @@ class GladiaSTTService(WebsocketSTTService): self._url = url self._receive_task = None + # Init-only connection config + self._encoding = encoding + self._bit_depth = bit_depth + self._channels = channels + # Session management self._session_url = None self._session_id = None @@ -372,14 +418,14 @@ class GladiaSTTService(WebsocketSTTService): """ return language_to_gladia_language(language) - def _prepare_settings(self) -> Dict[str, Any]: + def _prepare_settings(self) -> dict[str, Any]: s = self._settings settings = { - "encoding": s.encoding or "wav/pcm", - "bit_depth": s.bit_depth or 16, + "encoding": self._encoding or "wav/pcm", + "bit_depth": self._bit_depth or 16, "sample_rate": self.sample_rate, - "channels": s.channels or 1, + "channels": self._channels or 1, "model": s.model, } @@ -571,7 +617,7 @@ class GladiaSTTService(WebsocketSTTService): self._websocket = None await self._call_event_handler("on_disconnected") - async def _setup_gladia(self, settings: Dict[str, Any]): + async def _setup_gladia(self, settings: dict[str, Any]): async with aiohttp.ClientSession() as session: params = {} if self._region: diff --git a/src/pipecat/services/google/gemini_live/llm.py b/src/pipecat/services/google/gemini_live/llm.py index 2ed11c739..146a0fcc4 100644 --- a/src/pipecat/services/google/gemini_live/llm.py +++ b/src/pipecat/services/google/gemini_live/llm.py @@ -76,7 +76,7 @@ from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAIUserContextAggregator, ) -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.string import match_endofsentence from pipecat.utils.time import time_now_iso8601 @@ -552,6 +552,9 @@ class ContextWindowCompressionParams(BaseModel): class InputParams(BaseModel): """Input parameters for Gemini Live generation. + .. deprecated:: + Use ``GeminiLiveLLMSettings`` instead. + Parameters: frequency_penalty: Frequency penalty for generation (0.0-2.0). Defaults to None. max_tokens: Maximum tokens to generate. Must be >= 1. Defaults to 4096. @@ -607,6 +610,7 @@ class GeminiLiveLLMSettings(LLMSettings): """Settings for Gemini Live LLM services. Parameters: + voice: TTS voice identifier (e.g. ``"Charon"``). modalities: Response modalities. language: Language for generation. media_resolution: Media resolution setting. @@ -617,6 +621,7 @@ class GeminiLiveLLMSettings(LLMSettings): proactivity: Proactivity configuration. """ + voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) modalities: GeminiModalities | _NotGiven = field(default_factory=lambda: NOT_GIVEN) language: Language | str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) media_resolution: GeminiMediaResolution | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -647,13 +652,14 @@ class GeminiLiveLLMService(LLMService): *, api_key: str, base_url: Optional[str] = None, - model="models/gemini-2.5-flash-native-audio-preview-12-2025", + model: Optional[str] = None, voice_id: str = "Charon", start_audio_paused: bool = False, start_video_paused: bool = False, system_instruction: Optional[str] = None, tools: Optional[Union[List[dict], ToolsSchema]] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiLiveLLMSettings] = None, inference_on_context_initialization: bool = True, file_api_base_url: str = "https://generativelanguage.googleapis.com/v1beta/files", http_options: Optional[HttpOptions] = None, @@ -670,13 +676,26 @@ class GeminiLiveLLMService(LLMService): Please use `http_options` to customize requests made by the API client. - model: Model identifier to use. Defaults to "models/gemini-2.5-flash-native-audio-preview-12-2025". + model: Model identifier to use. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(model=...)`` instead. + voice_id: TTS voice identifier. Defaults to "Charon". + + .. deprecated:: 0.0.105 + Use ``settings=GeminiLiveLLMSettings(voice=...)`` instead. start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. system_instruction: System prompt for the model. Defaults to None. tools: Tools/functions available to the model. Defaults to None. - params: Configuration parameters for the model. Defaults to InputParams(). + params: Configuration parameters for the model. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(...)`` instead. + + settings: Gemini Live LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. inference_on_context_initialization: Whether to generate a response when context is first set. Defaults to True. file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint. @@ -695,42 +714,78 @@ class GeminiLiveLLMService(LLMService): stacklevel=2, ) - params = params or InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GeminiLiveLLMSettings( + model="models/gemini-2.5-flash-native-audio-preview-12-2025", + voice="Charon", + frequency_penalty=None, + max_tokens=4096, + presence_penalty=None, + temperature=None, + top_k=None, + top_p=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + modalities=GeminiModalities.AUDIO, + language="en-US", + media_resolution=GeminiMediaResolution.UNSPECIFIED, + vad=None, + context_window_compression={}, + thinking={}, + enable_affective_dialog=False, + proactivity={}, + extra={}, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GeminiLiveLLMSettings, "model") + default_settings.model = model + if voice_id != "Charon": + _warn_deprecated_param("voice_id", GeminiLiveLLMSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GeminiLiveLLMSettings) + if not settings: + default_settings.frequency_penalty = params.frequency_penalty + default_settings.max_tokens = params.max_tokens + default_settings.presence_penalty = params.presence_penalty + default_settings.temperature = params.temperature + default_settings.top_k = params.top_k + default_settings.top_p = params.top_p + default_settings.modalities = params.modalities + default_settings.language = ( + language_to_gemini_language(params.language) if params.language else "en-US" + ) + default_settings.media_resolution = params.media_resolution + default_settings.vad = params.vad + default_settings.context_window_compression = ( + params.context_window_compression.model_dump() + if params.context_window_compression + else {} + ) + default_settings.thinking = params.thinking or {} + default_settings.enable_affective_dialog = params.enable_affective_dialog or False + default_settings.proactivity = params.proactivity or {} + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( base_url=base_url, - settings=GeminiLiveLLMSettings( - model=model, - frequency_penalty=params.frequency_penalty, - max_tokens=params.max_tokens, - presence_penalty=params.presence_penalty, - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - modalities=params.modalities, - language=language_to_gemini_language(params.language) - if params.language - else "en-US", - media_resolution=params.media_resolution, - vad=params.vad, - context_window_compression=params.context_window_compression.model_dump() - if params.context_window_compression - else {}, - thinking=params.thinking or {}, - enable_affective_dialog=params.enable_affective_dialog or False, - proactivity=params.proactivity or {}, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), + settings=default_settings, **kwargs, ) self._last_sent_time = 0 self._base_url = base_url - self._voice_id = voice_id - self._language_code = params.language + self._language_code = params.language if params is not None else Language.EN_US self._system_instruction_from_init = system_instruction self._tools_from_init = tools @@ -760,11 +815,11 @@ class GeminiLiveLLMService(LLMService): self._sample_rate = 24000 - self._language = params.language + self._language = _params.language self._language_code = ( - language_to_gemini_language(params.language) if params.language else "en-US" + language_to_gemini_language(_params.language) if _params.language else "en-US" ) - self._vad_params = params.vad + self._vad_params = _params.vad # Reconnection tracking self._consecutive_failures = 0 @@ -1137,7 +1192,7 @@ class GeminiLiveLLMService(LLMService): response_modalities=[Modality(self._settings.modalities.value)], speech_config=SpeechConfig( voice_config=VoiceConfig( - prebuilt_voice_config={"voice_name": self._voice_id} + prebuilt_voice_config={"voice_name": self._settings.voice} ), language_code=self._settings.language, ), diff --git a/src/pipecat/services/google/gemini_live/llm_vertex.py b/src/pipecat/services/google/gemini_live/llm_vertex.py index bb61033b3..6264ea285 100644 --- a/src/pipecat/services/google/gemini_live/llm_vertex.py +++ b/src/pipecat/services/google/gemini_live/llm_vertex.py @@ -12,6 +12,7 @@ streaming responses, and tool usage. """ import json +from dataclasses import dataclass from typing import List, Optional, Union from loguru import logger @@ -19,9 +20,14 @@ from loguru import logger from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.services.google.gemini_live.llm import ( GeminiLiveLLMService, + GeminiLiveLLMSettings, + GeminiMediaResolution, + GeminiModalities, HttpOptions, InputParams, + language_to_gemini_language, ) +from pipecat.services.settings import _warn_deprecated_param try: from google.auth import default @@ -36,6 +42,13 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +@dataclass +class GeminiLiveVertexLLMSettings(GeminiLiveLLMSettings): + """Settings for Gemini Live Vertex LLM service.""" + + pass + + class GeminiLiveVertexLLMService(GeminiLiveLLMService): """Provides access to Google's Gemini Live model via Vertex AI. @@ -44,6 +57,8 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): responses, and tool usage. """ + _settings: GeminiLiveVertexLLMSettings + def __init__( self, *, @@ -51,13 +66,14 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): credentials_path: Optional[str] = None, location: str, project_id: str, - model="google/gemini-live-2.5-flash-native-audio", + model: Optional[str] = None, voice_id: str = "Charon", start_audio_paused: bool = False, start_video_paused: bool = False, system_instruction: Optional[str] = None, tools: Optional[Union[List[dict], ToolsSchema]] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiLiveVertexLLMSettings] = None, inference_on_context_initialization: bool = True, file_api_base_url: str = "https://generativelanguage.googleapis.com/v1beta/files", http_options: Optional[HttpOptions] = None, @@ -70,14 +86,27 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): credentials_path: Path to the service account JSON file. location: GCP region for Vertex AI endpoint (e.g., "us-east4"). project_id: Google Cloud project ID. - model: Model identifier to use. Defaults to "models/gemini-live-2.5-flash-native-audio". + model: Model identifier to use. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(model=...)`` instead. + voice_id: TTS voice identifier. Defaults to "Charon". + + .. deprecated:: 0.0.105 + Use ``settings=GeminiLiveVertexLLMSettings(voice=...)`` instead. start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. system_instruction: System prompt for the model. Defaults to None. tools: Tools/functions available to the model. Defaults to None. params: Configuration parameters for the model along with Vertex AI location and project ID. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(...)`` instead. + + settings: Gemini Live LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. inference_on_context_initialization: Whether to generate a response when context is first set. Defaults to True. file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint. @@ -101,18 +130,83 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): self._project_id = project_id self._location = location - # Call parent constructor with the obtained API key + # Build default_settings from deprecated args, then apply settings delta. + # We pass settings= to super() instead of model=/params= to avoid + # double deprecation warnings from the parent. + + # 1. Initialize default_settings with hardcoded defaults + default_settings = GeminiLiveVertexLLMSettings( + model="google/gemini-live-2.5-flash-native-audio", + voice="Charon", + frequency_penalty=None, + max_tokens=4096, + presence_penalty=None, + temperature=None, + top_k=None, + top_p=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + modalities=GeminiModalities.AUDIO, + language="en-US", + media_resolution=GeminiMediaResolution.UNSPECIFIED, + vad=None, + context_window_compression={}, + thinking={}, + enable_affective_dialog=False, + proactivity={}, + extra={}, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GeminiLiveVertexLLMSettings, "model") + default_settings.model = model + if voice_id != "Charon": + _warn_deprecated_param("voice_id", GeminiLiveVertexLLMSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GeminiLiveVertexLLMSettings) + if not settings: + default_settings.frequency_penalty = params.frequency_penalty + default_settings.max_tokens = params.max_tokens + default_settings.presence_penalty = params.presence_penalty + default_settings.temperature = params.temperature + default_settings.top_k = params.top_k + default_settings.top_p = params.top_p + default_settings.modalities = params.modalities + default_settings.language = ( + language_to_gemini_language(params.language) if params.language else "en-US" + ) + default_settings.media_resolution = params.media_resolution + default_settings.vad = params.vad + default_settings.context_window_compression = ( + params.context_window_compression.model_dump() + if params.context_window_compression + else {} + ) + default_settings.thinking = params.thinking or {} + default_settings.enable_affective_dialog = params.enable_affective_dialog or False + default_settings.proactivity = params.proactivity or {} + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + # Call parent constructor with the obtained settings super().__init__( # api_key is required by parent class, but actually not used with # Vertex api_key="dummy", - model=model, - voice_id=voice_id, start_audio_paused=start_audio_paused, start_video_paused=start_video_paused, system_instruction=system_instruction, tools=tools, - params=params, + settings=default_settings, inference_on_context_initialization=inference_on_context_initialization, file_api_base_url=file_api_base_url, http_options=http_options, diff --git a/src/pipecat/services/google/image.py b/src/pipecat/services/google/image.py index e69faf65e..4c351cc6e 100644 --- a/src/pipecat/services/google/image.py +++ b/src/pipecat/services/google/image.py @@ -16,7 +16,7 @@ import os # Suppress gRPC fork warnings os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "false" -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -26,7 +26,7 @@ from pydantic import BaseModel, Field from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.google.utils import update_google_client_http_options from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import NOT_GIVEN, ImageGenSettings, _NotGiven, _warn_deprecated_param try: from google import genai @@ -43,8 +43,13 @@ class GoogleImageGenSettings(ImageGenSettings): Parameters: model: Google Imagen model identifier. + number_of_images: Number of images to generate per request. + negative_prompt: Text describing what not to include in generated images. """ + number_of_images: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + negative_prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + class GoogleImageGenService(ImageGenService): """Google AI image generation service using Imagen models. @@ -57,6 +62,9 @@ class GoogleImageGenService(ImageGenService): class InputParams(BaseModel): """Configuration parameters for Google image generation. + .. deprecated:: 0.0.105 + Use ``settings=GoogleImageGenSettings(...)`` instead. + Parameters: number_of_images: Number of images to generate (1-8). Defaults to 1. model: Google Imagen model to use. Defaults to "imagen-3.0-generate-002". @@ -67,25 +75,51 @@ class GoogleImageGenService(ImageGenService): model: str = Field(default="imagen-3.0-generate-002") negative_prompt: Optional[str] = Field(default=None) + _settings: GoogleImageGenSettings + def __init__( self, *, api_key: str, params: Optional[InputParams] = None, http_options: Optional[Any] = None, + settings: Optional[GoogleImageGenSettings] = None, **kwargs, ): """Initialize the GoogleImageGenService with API key and parameters. Args: api_key: Google AI API key for authentication. - params: Configuration parameters for image generation. Defaults to InputParams(). + params: Configuration parameters for image generation. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleImageGenSettings(...)`` instead. + http_options: HTTP options for the client. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent ImageGenService. """ - params = params or GoogleImageGenService.InputParams() - super().__init__(settings=GoogleImageGenSettings(model=params.model), **kwargs) - self._params = params + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleImageGenSettings( + model="imagen-3.0-generate-002", + number_of_images=1, + negative_prompt=None, + ) + + # 2. Apply params overrides (deprecated) + if params is not None: + _warn_deprecated_param("params", GoogleImageGenSettings) + if not settings: + default_settings.model = params.model + default_settings.number_of_images = params.number_of_images + default_settings.negative_prompt = params.negative_prompt + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) # Add client header http_options = update_google_client_http_options(http_options) @@ -118,11 +152,11 @@ class GoogleImageGenService(ImageGenService): try: response = await self._client.aio.models.generate_images( - model=self._params.model, + model=self._settings.model, prompt=prompt, config=types.GenerateImagesConfig( - number_of_images=self._params.number_of_images, - negative_prompt=self._params.negative_prompt, + number_of_images=self._settings.number_of_images, + negative_prompt=self._settings.negative_prompt, ), ) await self.stop_ttfb_metrics() diff --git a/src/pipecat/services/google/llm.py b/src/pipecat/services/google/llm.py index 37ccfae9a..980d2d576 100644 --- a/src/pipecat/services/google/llm.py +++ b/src/pipecat/services/google/llm.py @@ -58,7 +58,13 @@ from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAIUserContextAggregator, ) -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + LLMSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.utils.tracing.service_decorators import traced_llm # Suppress gRPC fork warnings @@ -748,6 +754,9 @@ class GoogleLLMService(LLMService): class InputParams(BaseModel): """Input parameters for Google AI models. + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + Parameters: max_tokens: Maximum number of tokens to generate. temperature: Sampling temperature between 0.0 and 2.0. @@ -773,8 +782,9 @@ class GoogleLLMService(LLMService): self, *, api_key: str, - model: str = "gemini-2.5-flash", + model: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[List[Dict[str, Any]]] = None, tool_config: Optional[Dict[str, Any]] = None, @@ -785,36 +795,72 @@ class GoogleLLMService(LLMService): Args: api_key: Google AI API key for authentication. - model: Model name to use. Defaults to "gemini-2.0-flash". - params: Input parameters for the model. + model: Model name to use. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(model=...)`` instead. + + params: Optional model parameters for inference. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. system_instruction: System instruction/prompt for the model. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleLLMSettings(system_instruction=...)`` instead. tools: List of available tools/functions. tool_config: Configuration for tool usage. http_options: HTTP options for the client. **kwargs: Additional arguments passed to parent class. """ - params = params or GoogleLLMService.InputParams() - - super().__init__( - settings=GoogleLLMSettings( - model=model, - max_tokens=params.max_tokens, - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - thinking=params.thinking, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), - **kwargs, + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleLLMSettings( + model="gemini-2.5-flash", + system_instruction=None, + max_tokens=4096, + temperature=None, + top_k=None, + top_p=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + thinking=None, + extra={}, ) + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GoogleLLMSettings, "model") + default_settings.model = model + if system_instruction is not None: + _warn_deprecated_param("system_instruction", GoogleLLMSettings, "system_instruction") + default_settings.system_instruction = system_instruction + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GoogleLLMSettings) + if not settings: + default_settings.max_tokens = params.max_tokens + default_settings.temperature = params.temperature + default_settings.top_k = params.top_k + default_settings.top_p = params.top_p + default_settings.thinking = params.thinking + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) + self._api_key = api_key - self._system_instruction = system_instruction self._http_options = update_google_client_http_options(http_options) self._tools = tools self._tool_config = tool_config @@ -953,10 +999,10 @@ class GoogleLLMService(LLMService): messages = params_from_context["messages"] if ( params_from_context["system_instruction"] - and self._system_instruction != params_from_context["system_instruction"] + and self._settings.system_instruction != params_from_context["system_instruction"] ): logger.debug(f"System instruction changed: {params_from_context['system_instruction']}") - self._system_instruction = params_from_context["system_instruction"] + self._settings.system_instruction = params_from_context["system_instruction"] tools = [] if params_from_context["tools"]: @@ -969,7 +1015,9 @@ class GoogleLLMService(LLMService): # Build generation parameters generation_params = self._build_generation_params( - system_instruction=self._system_instruction, tools=tools, tool_config=tool_config + system_instruction=self._settings.system_instruction, + tools=tools, + tool_config=tool_config, ) # possibly modify generation_params (in place) to set thinking to off by default diff --git a/src/pipecat/services/google/llm_openai.py b/src/pipecat/services/google/llm_openai.py index 5d396b583..96e208fcb 100644 --- a/src/pipecat/services/google/llm_openai.py +++ b/src/pipecat/services/google/llm_openai.py @@ -12,6 +12,8 @@ API format through Google's Gemini API OpenAI compatibility layer. import json import os +from dataclasses import dataclass +from typing import Optional from openai import AsyncStream from openai.types.chat import ChatCompletionChunk @@ -26,7 +28,16 @@ from loguru import logger from pipecat.frames.frames import LLMTextFrame from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class GoogleOpenAILLMSettings(OpenAILLMSettings): + """Settings for Google OpenAI-compatible LLM service.""" + + pass class GoogleLLMOpenAIBetaService(OpenAILLMService): @@ -47,12 +58,15 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): https://ai.google.dev/gemini-api/docs/openai """ + _settings: GoogleOpenAILLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://generativelanguage.googleapis.com/v1beta/openai/", - model: str = "gemini-2.0-flash", + model: Optional[str] = None, + settings: Optional[GoogleOpenAILLMSettings] = None, **kwargs, ): """Initialize the Google LLM service. @@ -61,6 +75,12 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): api_key: Google API key for authentication. base_url: Base URL for Google's OpenAI-compatible API. model: Google model name to use (e.g., "gemini-2.0-flash"). + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent OpenAILLMService. """ import warnings @@ -74,7 +94,19 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): stacklevel=2, ) - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleOpenAILLMSettings(model="gemini-2.0-flash") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GoogleOpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) async def _process_context(self, context: OpenAILLMContext): functions_list = [] diff --git a/src/pipecat/services/google/llm_vertex.py b/src/pipecat/services/google/llm_vertex.py index ef222c97e..42d96333c 100644 --- a/src/pipecat/services/google/llm_vertex.py +++ b/src/pipecat/services/google/llm_vertex.py @@ -12,6 +12,7 @@ extending the GoogleLLMService with Vertex AI authentication. import json import os +from dataclasses import dataclass # Suppress gRPC fork warnings os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "false" @@ -20,7 +21,8 @@ from typing import Optional from loguru import logger -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.settings import _warn_deprecated_param try: from google.auth import default @@ -38,6 +40,13 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +@dataclass +class GoogleVertexLLMSettings(GoogleLLMSettings): + """Settings for Google Vertex LLM service.""" + + pass + + class GoogleVertexLLMService(GoogleLLMService): """Google Vertex AI LLM service extending GoogleLLMService. @@ -50,6 +59,8 @@ class GoogleVertexLLMService(GoogleLLMService): https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference """ + _settings: GoogleVertexLLMSettings + class InputParams(GoogleLLMService.InputParams): """Input parameters specific to Vertex AI. @@ -99,10 +110,11 @@ class GoogleVertexLLMService(GoogleLLMService): *, credentials: Optional[str] = None, credentials_path: Optional[str] = None, - model: str = "gemini-2.5-flash", + model: Optional[str] = None, location: Optional[str] = None, project_id: Optional[str] = None, params: Optional[GoogleLLMService.InputParams] = None, + settings: Optional[GoogleVertexLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[list] = None, tool_config: Optional[dict] = None, @@ -115,10 +127,24 @@ class GoogleVertexLLMService(GoogleLLMService): credentials: JSON string of service account credentials. credentials_path: Path to the service account JSON file. model: Model identifier (e.g., "gemini-2.5-flash"). + + .. deprecated:: + Use ``settings=GoogleLLMSettings(model=...)`` instead. + location: GCP region for Vertex AI endpoint (e.g., "us-east4"). project_id: Google Cloud project ID. params: Input parameters for the model. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. system_instruction: System instruction/prompt for the model. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleVertexLLMSettings(system_instruction=...)`` instead. tools: List of available tools/functions. tool_config: Configuration for tool usage. http_options: HTTP options for the client. @@ -135,10 +161,9 @@ class GoogleVertexLLMService(GoogleLLMService): "Invalid parameter 'api_key'. Use 'credentials' or 'credentials_path' for Vertex AI authentication." ) - # Handle deprecated InputParams fields + # Handle deprecated InputParams fields (location/project_id extraction + # must happen before validation, regardless of settings) if params and isinstance(params, GoogleVertexLLMService.InputParams): - # Extract location and project_id from params if not provided - # directly, for backward compatibility if project_id is None: project_id = params.project_id if location is None: @@ -170,13 +195,54 @@ class GoogleVertexLLMService(GoogleLLMService): self._project_id = project_id self._location = location + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleVertexLLMSettings( + model="gemini-2.5-flash", + system_instruction=None, + max_tokens=4096, + temperature=None, + top_k=None, + top_p=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + thinking=None, + extra={}, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GoogleVertexLLMSettings, "model") + default_settings.model = model + if system_instruction is not None: + _warn_deprecated_param( + "system_instruction", GoogleVertexLLMSettings, "system_instruction" + ) + default_settings.system_instruction = system_instruction + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GoogleVertexLLMSettings) + if not settings: + default_settings.max_tokens = params.max_tokens + default_settings.temperature = params.temperature + default_settings.top_k = params.top_k + default_settings.top_p = params.top_p + default_settings.thinking = params.thinking + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + # Call parent constructor with dummy api_key # (api_key is required by parent class, but not actually used with Vertex) super().__init__( api_key="dummy", - model=model, - params=params, - system_instruction=system_instruction, + settings=default_settings, tools=tools, tool_config=tool_config, http_options=http_options, diff --git a/src/pipecat/services/google/stt.py b/src/pipecat/services/google/stt.py index 95d91d462..376e74a6d 100644 --- a/src/pipecat/services/google/stt.py +++ b/src/pipecat/services/google/stt.py @@ -36,7 +36,7 @@ from pipecat.frames.frames import ( StartFrame, TranscriptionFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import GOOGLE_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -425,6 +425,9 @@ class GoogleSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for Google Speech-to-Text. + .. deprecated:: 0.0.105 + Use ``settings=GoogleSTTSettings(...)`` instead. + Parameters: languages: Single language or list of recognition languages. First language is primary. model: Speech recognition model to use. @@ -484,6 +487,7 @@ class GoogleSTTService(STTService): location: str = "global", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleSTTSettings] = None, ttfs_p99_latency: Optional[float] = GOOGLE_TTFS_P99, **kwargs, ): @@ -495,30 +499,61 @@ class GoogleSTTService(STTService): location: Google Cloud location (e.g., "global", "us-central1"). sample_rate: Audio sample rate in Hertz. params: Configuration parameters for the service. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + ``params``, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - params = params or GoogleSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleSTTSettings( + language=None, + languages=[Language.EN_US], + language_codes=None, + model="latest_long", + use_separate_recognition_per_channel=False, + enable_automatic_punctuation=True, + enable_spoken_punctuation=False, + enable_spoken_emojis=False, + profanity_filter=False, + enable_word_time_offsets=False, + enable_word_confidence=False, + enable_interim_results=True, + enable_voice_activity_events=False, + ) + + # 2. No direct init arg overrides + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GoogleSTTSettings) + if not settings: + default_settings.languages = list(params.language_list) + default_settings.model = params.model + default_settings.use_separate_recognition_per_channel = ( + params.use_separate_recognition_per_channel + ) + default_settings.enable_automatic_punctuation = params.enable_automatic_punctuation + default_settings.enable_spoken_punctuation = params.enable_spoken_punctuation + default_settings.enable_spoken_emojis = params.enable_spoken_emojis + default_settings.profanity_filter = params.profanity_filter + default_settings.enable_word_time_offsets = params.enable_word_time_offsets + default_settings.enable_word_confidence = params.enable_word_confidence + default_settings.enable_interim_results = params.enable_interim_results + default_settings.enable_voice_activity_events = params.enable_voice_activity_events + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=GoogleSTTSettings( - language=None, - languages=list(params.language_list), - language_codes=None, - model=params.model, - use_separate_recognition_per_channel=params.use_separate_recognition_per_channel, - enable_automatic_punctuation=params.enable_automatic_punctuation, - enable_spoken_punctuation=params.enable_spoken_punctuation, - enable_spoken_emojis=params.enable_spoken_emojis, - profanity_filter=params.profanity_filter, - enable_word_time_offsets=params.enable_word_time_offsets, - enable_word_confidence=params.enable_word_confidence, - enable_interim_results=params.enable_interim_results, - enable_voice_activity_events=params.enable_voice_activity_events, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/google/tts.py b/src/pipecat/services/google/tts.py index 6c71977a0..7cf2ee996 100644 --- a/src/pipecat/services/google/tts.py +++ b/src/pipecat/services/google/tts.py @@ -37,7 +37,13 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + TTSSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language @@ -488,7 +494,6 @@ class GoogleHttpTTSSettings(TTSSettings): Range [0.25, 2.0]. volume: Volume adjustment (e.g., "loud", "soft", "+6dB"). emphasis: Emphasis level for the text. - language: Language for synthesis. Defaults to English. gender: Voice gender preference. google_style: Google-specific voice style. """ @@ -500,7 +505,6 @@ class GoogleHttpTTSSettings(TTSSettings): emphasis: Literal["strong", "moderate", "reduced", "none"] | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) - language: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) gender: Literal["male", "female", "neutral"] | None | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) @@ -514,11 +518,9 @@ class GoogleStreamTTSSettings(TTSSettings): """Settings for Google streaming TTS service. Parameters: - language: Language for synthesis. Defaults to English. speaking_rate: The speaking rate, in the range [0.25, 2.0]. """ - language: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speaking_rate: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -527,13 +529,11 @@ class GeminiTTSSettings(TTSSettings): """Settings for Gemini TTS service. Parameters: - language: Language for synthesis. Defaults to English. prompt: Optional style instructions for how to synthesize the content. multi_speaker: Whether to enable multi-speaker support. speaker_configs: List of speaker configurations for multi-speaker mode. """ - language: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) multi_speaker: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speaker_configs: list[dict[str, Any]] | None | _NotGiven = field( @@ -560,6 +560,9 @@ class GoogleHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Google HTTP TTS voice customization. + .. deprecated:: 0.0.105 + Use ``GoogleHttpTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: pitch: Voice pitch adjustment (e.g., "+2st", "-50%"). rate: Speaking rate adjustment (e.g., "slow", "fast", "125%"). Used for SSML prosody tags (non-Chirp voices). @@ -586,9 +589,10 @@ class GoogleHttpTTSService(TTSService): credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "en-US-Chirp3-HD-Charon", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleHttpTTSSettings] = None, **kwargs, ): """Initializes the Google HTTP TTS service. @@ -598,28 +602,60 @@ class GoogleHttpTTSService(TTSService): credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Google TTS voice identifier (e.g., "en-US-Standard-A"). + + .. deprecated:: 0.0.105 + Use ``settings=GoogleHttpTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses default. params: Voice customization parameters including pitch, rate, volume, etc. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or GoogleHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleHttpTTSSettings( + model=None, + voice="en-US-Chirp3-HD-Charon", + language="en-US", + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", GoogleHttpTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GoogleHttpTTSSettings) + if not settings: + if params.pitch is not None: + default_settings.pitch = params.pitch + if params.rate is not None: + default_settings.rate = params.rate + if params.speaking_rate is not None: + default_settings.speaking_rate = params.speaking_rate + if params.volume is not None: + default_settings.volume = params.volume + if params.emphasis is not None: + default_settings.emphasis = params.emphasis + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.gender is not None: + default_settings.gender = params.gender + if params.google_style is not None: + default_settings.google_style = params.google_style + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=GoogleHttpTTSSettings( - model=None, - pitch=params.pitch, - rate=params.rate, - speaking_rate=params.speaking_rate, - volume=params.volume, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - gender=params.gender, - google_style=params.google_style, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -987,6 +1023,9 @@ class GoogleTTSService(GoogleBaseTTSService): class InputParams(BaseModel): """Input parameters for Google streaming TTS configuration. + .. deprecated:: 0.0.105 + Use ``GoogleStreamTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English. speaking_rate: The speaking rate, in the range [0.25, 2.0]. @@ -1001,10 +1040,11 @@ class GoogleTTSService(GoogleBaseTTSService): credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "en-US-Chirp3-HD-Charon", + voice_id: Optional[str] = None, voice_cloning_key: Optional[str] = None, sample_rate: Optional[int] = None, - params: InputParams = InputParams(), + params: Optional[InputParams] = None, + settings: Optional[GoogleStreamTTSSettings] = None, **kwargs, ): """Initializes the Google streaming TTS service. @@ -1014,23 +1054,49 @@ class GoogleTTSService(GoogleBaseTTSService): credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Google TTS voice identifier (e.g., "en-US-Chirp3-HD-Charon"). + + .. deprecated:: 0.0.105 + Use ``settings=GoogleStreamTTSSettings(voice=...)`` instead. + voice_cloning_key: The voice cloning key for Chirp 3 custom voices. sample_rate: Audio sample rate in Hz. If None, uses default. params: Language configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=GoogleStreamTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or GoogleTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleStreamTTSSettings( + model=None, + voice="en-US-Chirp3-HD-Charon", + language="en-US", + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", GoogleStreamTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GoogleStreamTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.speaking_rate is not None: + default_settings.speaking_rate = params.speaking_rate + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=GoogleStreamTTSSettings( - model=None, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - speaking_rate=params.speaking_rate, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -1170,6 +1236,9 @@ class GeminiTTSService(GoogleBaseTTSService): class InputParams(BaseModel): """Input parameters for Gemini TTS configuration. + .. deprecated:: 0.0.105 + Use ``GeminiTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English. prompt: Optional style instructions for how to synthesize the content. @@ -1186,13 +1255,14 @@ class GeminiTTSService(GoogleBaseTTSService): self, *, api_key: Optional[str] = None, - model: str = "gemini-2.5-flash-tts", + model: Optional[str] = None, credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "Kore", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiTTSSettings] = None, **kwargs, ): """Initializes the Gemini TTS service. @@ -1206,12 +1276,26 @@ class GeminiTTSService(GoogleBaseTTSService): model: Gemini TTS model to use. Must be a TTS model like "gemini-2.5-flash-tts" or "gemini-2.5-pro-tts". + + .. deprecated:: 0.0.105 + Use ``settings=GeminiTTSSettings(model=...)`` instead. + credentials: JSON string containing Google Cloud service account credentials. credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Voice name from the available Gemini voices. + + .. deprecated:: 0.0.105 + Use ``settings=GeminiTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses Google's default 24kHz. params: TTS configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=GeminiTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ # Handle deprecated api_key parameter @@ -1228,23 +1312,47 @@ class GeminiTTSService(GoogleBaseTTSService): f"Google TTS only supports {self.GOOGLE_SAMPLE_RATE}Hz sample rate. " f"Current rate of {sample_rate}Hz may cause issues." ) - params = params or GeminiTTSService.InputParams() - if voice_id not in self.AVAILABLE_VOICES: - logger.warning(f"Voice '{voice_id}' not in known voices list. Using anyway.") + # 1. Initialize default_settings with hardcoded defaults + default_settings = GeminiTTSSettings( + model="gemini-2.5-flash-tts", + voice="Kore", + language="en-US", + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GeminiTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", GeminiTTSSettings, "voice") + default_settings.voice = voice_id + + if default_settings.voice not in self.AVAILABLE_VOICES: + logger.warning( + f"Voice '{default_settings.voice}' not in known voices list. Using anyway." + ) + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GeminiTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.prompt is not None: + default_settings.prompt = params.prompt + if params.multi_speaker is not None: + default_settings.multi_speaker = params.multi_speaker + if params.speaker_configs is not None: + default_settings.speaker_configs = params.speaker_configs + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=GeminiTTSSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - prompt=params.prompt, - multi_speaker=params.multi_speaker, - speaker_configs=params.speaker_configs, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/gradium/stt.py b/src/pipecat/services/gradium/stt.py index ac35c6e52..e8ab072d0 100644 --- a/src/pipecat/services/gradium/stt.py +++ b/src/pipecat/services/gradium/stt.py @@ -12,7 +12,7 @@ WebSocket API for streaming audio transcription. import base64 import json -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -28,7 +28,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import STTSettings, _warn_deprecated_param from pipecat.services.stt_latency import GRADIUM_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -68,14 +68,9 @@ def language_to_gradium_language(language: Language) -> Optional[str]: @dataclass class GradiumSTTSettings(STTSettings): - """Settings for the Gradium STT service. + """Settings for the Gradium STT service.""" - Parameters: - delay_in_frames: Delay in audio frames (80ms each) before text is - generated. Higher delays allow more context but increase latency. - """ - - delay_in_frames: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class GradiumSTTService(WebsocketSTTService): @@ -91,6 +86,9 @@ class GradiumSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for Gradium STT API. + .. deprecated:: 0.0.105 + Use ``settings=GradiumSTTSettings(...)`` instead. + Parameters: language: Expected language of the audio (e.g., "en", "es", "fr"). This helps ground the model to a specific language and improve @@ -109,8 +107,10 @@ class GradiumSTTService(WebsocketSTTService): *, api_key: str, api_endpoint_base_url: str = "wss://eu.api.gradium.ai/api/speech/asr", + delay_in_frames: Optional[int] = None, params: Optional[InputParams] = None, json_config: Optional[str] = None, + settings: Optional[GradiumSTTSettings] = None, ttfs_p99_latency: Optional[float] = GRADIUM_TTFS_P99, **kwargs, ): @@ -119,12 +119,21 @@ class GradiumSTTService(WebsocketSTTService): Args: api_key: Gradium API key for authentication. api_endpoint_base_url: WebSocket endpoint URL. Defaults to Gradium's streaming endpoint. + delay_in_frames: Delay in audio frames (80ms each) before text is + generated. Higher delays allow more context but increase latency. + Allowed values: 7, 8, 10, 12, 14, 16, 20, 24, 36, 48. params: Configuration parameters for language and delay settings. + + .. deprecated:: 0.0.105 + Use ``settings=GradiumSTTSettings(...)`` instead. + json_config: Optional JSON configuration string for additional model settings. .. deprecated:: 0.0.101 Use `params` instead for type-safe configuration. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. @@ -138,16 +147,30 @@ class GradiumSTTService(WebsocketSTTService): stacklevel=2, ) - params = params or GradiumSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GradiumSTTSettings( + model=None, + language=None, + ) + + # 2. (no deprecated direct args for this service) + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GradiumSTTSettings) + if not settings: + default_settings.language = params.language + if params.delay_in_frames is not None: + delay_in_frames = params.delay_in_frames + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=SAMPLE_RATE, ttfs_p99_latency=ttfs_p99_latency, - settings=GradiumSTTSettings( - model=None, - language=params.language, - delay_in_frames=params.delay_in_frames or None, - ), + settings=default_settings, **kwargs, ) @@ -155,6 +178,7 @@ class GradiumSTTService(WebsocketSTTService): self._api_endpoint_base_url = api_endpoint_base_url self._websocket = None self._json_config = json_config + self._config_delay_in_frames = delay_in_frames self._receive_task = None @@ -334,8 +358,8 @@ class GradiumSTTService(WebsocketSTTService): gradium_language = language_to_gradium_language(self._settings.language) if gradium_language: json_config["language"] = gradium_language - if self._settings.delay_in_frames: - json_config["delay_in_frames"] = self._settings.delay_in_frames + if self._config_delay_in_frames: + json_config["delay_in_frames"] = self._config_delay_in_frames if json_config: setup_msg["json_config"] = json_config await self._websocket.send(json.dumps(setup_msg)) diff --git a/src/pipecat/services/gradium/tts.py b/src/pipecat/services/gradium/tts.py index c8a83a7f2..2ade14367 100644 --- a/src/pipecat/services/gradium/tts.py +++ b/src/pipecat/services/gradium/tts.py @@ -6,7 +6,7 @@ import base64 import json -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -22,7 +22,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -40,13 +40,9 @@ SAMPLE_RATE = 48000 @dataclass class GradiumTTSSettings(TTSSettings): - """Settings for the Gradium TTS service. + """Settings for the Gradium TTS service.""" - Parameters: - output_format: Audio output format. - """ - - output_format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class GradiumTTSService(AudioContextTTSService): @@ -57,6 +53,9 @@ class GradiumTTSService(AudioContextTTSService): class InputParams(BaseModel): """Configuration parameters for Gradium TTS service. + .. deprecated:: 0.0.105 + Use ``GradiumTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temp: Temperature to be used for generation, defaults to 0.6. """ @@ -67,11 +66,12 @@ class GradiumTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str = "YTpq7expH9539ERJ", + voice_id: Optional[str] = None, url: str = "wss://eu.api.gradium.ai/api/speech/tts", - model: str = "default", + model: Optional[str] = None, json_config: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[GradiumTTSSettings] = None, **kwargs, ): """Initialize the Gradium TTS service. @@ -79,13 +79,49 @@ class GradiumTTSService(AudioContextTTSService): Args: api_key: Gradium API key for authentication. voice_id: the voice identifier. + + .. deprecated:: 0.0.105 + Use ``settings=GradiumTTSSettings(voice=...)`` instead. + url: Gradium websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=GradiumTTSSettings(model=...)`` instead. + json_config: Optional JSON configuration string for additional model settings. params: Additional configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=GradiumTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent class. """ - params = params or GradiumTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GradiumTTSSettings( + model="default", + voice="YTpq7expH9539ERJ", + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GradiumTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", GradiumTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GradiumTTSSettings) + # Note: params.temp has no corresponding settings field + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_stop_frames=True, @@ -93,12 +129,7 @@ class GradiumTTSService(AudioContextTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=SAMPLE_RATE, - settings=GradiumTTSSettings( - model=model, - voice=voice_id, - language=None, - output_format="pcm", - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/grok/llm.py b/src/pipecat/services/grok/llm.py index fa905a92c..59741cf9a 100644 --- a/src/pipecat/services/grok/llm.py +++ b/src/pipecat/services/grok/llm.py @@ -12,6 +12,7 @@ and context aggregation functionality. """ from dataclasses import dataclass +from typing import Optional from loguru import logger @@ -22,11 +23,13 @@ from pipecat.processors.aggregators.llm_response import ( LLMUserAggregatorParams, ) from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAILLMService, OpenAIUserContextAggregator, ) +from pipecat.services.settings import _warn_deprecated_param @dataclass @@ -67,6 +70,13 @@ class GrokContextAggregatorPair: return self._assistant +@dataclass +class GrokLLMSettings(OpenAILLMSettings): + """Settings for Grok LLM service.""" + + pass + + class GrokLLMService(OpenAILLMService): """A service for interacting with Grok's API using the OpenAI-compatible interface. @@ -76,12 +86,15 @@ class GrokLLMService(OpenAILLMService): processing and reports final totals. """ + _settings: GrokLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.x.ai/v1", - model: str = "grok-3-beta", + model: Optional[str] = None, + settings: Optional[GrokLLMSettings] = None, **kwargs, ): """Initialize the GrokLLMService with API key and model. @@ -90,9 +103,27 @@ class GrokLLMService(OpenAILLMService): api_key: The API key for accessing Grok's API. base_url: The base URL for Grok API. Defaults to "https://api.x.ai/v1". model: The model identifier to use. Defaults to "grok-3-beta". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = GrokLLMSettings(model="grok-3-beta") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GrokLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Initialize counters for token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 diff --git a/src/pipecat/services/grok/realtime/llm.py b/src/pipecat/services/grok/realtime/llm.py index 7a4e73806..074b44c5d 100644 --- a/src/pipecat/services/grok/realtime/llm.py +++ b/src/pipecat/services/grok/realtime/llm.py @@ -13,7 +13,7 @@ https://docs.x.ai/docs/guides/voice/agent import base64 import json import time -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Optional from loguru import logger @@ -56,7 +56,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import LLMSettings from pipecat.utils.time import time_now_iso8601 from . import events @@ -88,15 +88,9 @@ class CurrentAudioResponse: @dataclass class GrokRealtimeLLMSettings(LLMSettings): - """Settings for Grok Realtime LLM services. + """Settings for Grok Realtime LLM services.""" - Parameters: - session_properties: Grok Realtime session configuration. - """ - - session_properties: events.SessionProperties | _NotGiven = field( - default_factory=lambda: NOT_GIVEN - ) + pass class GrokRealtimeLLMService(LLMService): @@ -126,6 +120,7 @@ class GrokRealtimeLLMService(LLMService): api_key: str, base_url: str = "wss://api.x.ai/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[GrokRealtimeLLMSettings] = None, start_audio_paused: bool = False, **kwargs, ): @@ -142,29 +137,38 @@ class GrokRealtimeLLMService(LLMService): session_properties = events.SessionProperties(voice="Rex") Available voices: Ara, Rex, Sal, Eve, Leo. + settings: Runtime-updatable settings for this service. start_audio_paused: Whether to start with audio input paused. Defaults to False. **kwargs: Additional arguments passed to parent LLMService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = GrokRealtimeLLMSettings( + model=None, + system_instruction=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + ) + + # 2. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( base_url=base_url, - settings=GrokRealtimeLLMSettings( - model=None, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) self.api_key = api_key self.base_url = base_url + self._session_properties = session_properties or events.SessionProperties() self._audio_input_paused = start_audio_paused self._websocket = None @@ -213,13 +217,13 @@ class GrokRealtimeLLMService(LLMService): Configured sample rate or None if not manually configured. For PCMU/PCMA formats, returns 8000 Hz (G.711 standard). """ - if not self._settings.session_properties.audio: + if not self._session_properties.audio: return None audio_config = ( - self._settings.session_properties.audio.input + self._session_properties.audio.input if direction == "input" - else self._settings.session_properties.audio.output + else self._session_properties.audio.output ) if audio_config and audio_config.format: @@ -249,8 +253,8 @@ class GrokRealtimeLLMService(LLMService): def _is_turn_detection_enabled(self) -> bool: """Check if server-side VAD is enabled.""" - if self._settings.session_properties.turn_detection: - return self._settings.session_properties.turn_detection.type == "server_vad" + if self._session_properties.turn_detection: + return self._session_properties.turn_detection.type == "server_vad" return False async def _handle_interruption(self): @@ -317,7 +321,7 @@ class GrokRealtimeLLMService(LLMService): input_sample_rate: Sample rate for audio input (Hz). output_sample_rate: Sample rate for audio output (Hz). """ - props = self._settings.session_properties + props = self._session_properties if not props.audio: props.audio = events.AudioConfiguration() if not props.audio.input: @@ -373,7 +377,12 @@ class GrokRealtimeLLMService(LLMService): # directly. The frame.delta path falls through to super, which calls # _update_settings → our override handles the rest. if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None: - self._settings.session_properties = events.SessionProperties(**frame.settings) + # Capture current audio config before replacing session properties. + input_rate = self._get_configured_sample_rate("input") + output_rate = self._get_configured_sample_rate("output") + self._session_properties = events.SessionProperties(**frame.settings) + if input_rate and output_rate: + self._ensure_audio_config(input_rate, output_rate) await self._send_session_update() await self.push_frame(frame, direction) return @@ -476,29 +485,14 @@ class GrokRealtimeLLMService(LLMService): await self.push_error(error_msg=f"Error sending client event: {e}", exception=e) async def _update_settings(self, delta): - """Apply a settings delta, sending a session update if needed.""" - # Capture current sample rates before the update replaces them. - input_rate = self._get_configured_sample_rate("input") - output_rate = self._get_configured_sample_rate("output") - + """Apply a settings delta.""" changed = await super()._update_settings(delta) - - if "session_properties" in changed: - if input_rate and output_rate: - self._ensure_audio_config(input_rate, output_rate) - else: - logger.warning( - "Attempting to apply session properties update without configured sample rates. " - "Audio configuration may be incomplete." - ) - await self._send_session_update() - - self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"}) + self._warn_unhandled_updated_settings(changed.keys()) return changed async def _send_session_update(self): """Update session settings on the server.""" - settings = self._settings.session_properties + settings = self._session_properties adapter: GrokRealtimeLLMAdapter = self.get_llm_adapter() if self._context: diff --git a/src/pipecat/services/groq/llm.py b/src/pipecat/services/groq/llm.py index 9dae88c31..d7fc7f939 100644 --- a/src/pipecat/services/groq/llm.py +++ b/src/pipecat/services/groq/llm.py @@ -6,9 +6,21 @@ """Groq LLM Service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class GroqLLMSettings(OpenAILLMSettings): + """Settings for Groq LLM service.""" + + pass class GroqLLMService(OpenAILLMService): @@ -18,12 +30,15 @@ class GroqLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: GroqLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.groq.com/openai/v1", - model: str = "llama-3.3-70b-versatile", + model: Optional[str] = None, + settings: Optional[GroqLLMSettings] = None, **kwargs, ): """Initialize Groq LLM service. @@ -32,9 +47,27 @@ class GroqLLMService(OpenAILLMService): api_key: The API key for accessing Groq's API. base_url: The base URL for Groq API. Defaults to "https://api.groq.com/openai/v1". model: The model identifier to use. Defaults to "llama-3.3-70b-versatile". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = GroqLLMSettings(model="llama-3.3-70b-versatile") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", GroqLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Groq API endpoint. diff --git a/src/pipecat/services/groq/stt.py b/src/pipecat/services/groq/stt.py index d51e93c68..1733831c8 100644 --- a/src/pipecat/services/groq/stt.py +++ b/src/pipecat/services/groq/stt.py @@ -6,13 +6,30 @@ """Groq speech-to-text service implementation using Whisper models.""" +from dataclasses import dataclass from typing import Optional +from pipecat.services.settings import _warn_deprecated_param from pipecat.services.stt_latency import GROQ_TTFS_P99 -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language +@dataclass +class GroqSTTSettings(BaseWhisperSTTSettings): + """Settings for the Groq STT service. + + Parameters: + prompt: Optional prompt text to guide transcription style. + """ + + pass + + class GroqSTTService(BaseWhisperSTTService): """Groq Whisper speech-to-text service. @@ -20,44 +37,90 @@ class GroqSTTService(BaseWhisperSTTService): set via the api_key parameter or GROQ_API_KEY environment variable. """ + _settings: GroqSTTSettings + def __init__( self, *, - model: str = "whisper-large-v3-turbo", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: str = "https://api.groq.com/openai/v1", - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[GroqSTTSettings] = None, ttfs_p99_latency: Optional[float] = GROQ_TTFS_P99, **kwargs, ): """Initialize Groq STT service. Args: - model: Whisper model to use. Defaults to "whisper-large-v3-turbo". + model: Whisper model to use. + + .. deprecated:: 0.0.105 + Use ``settings=GroqSTTSettings(model=...)`` instead. + api_key: Groq API key. Defaults to None. base_url: API base URL. Defaults to "https://api.groq.com/openai/v1". - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 0.0.105 + Use ``settings=GroqSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 0.0.105 + Use ``settings=GroqSTTSettings(prompt=...)`` instead. + + temperature: Optional sampling temperature between 0 and 1. + + .. deprecated:: 0.0.105 + Use ``settings=GroqSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ + # --- 1. Hardcoded defaults --- + default_settings = GroqSTTSettings( + model="whisper-large-v3-turbo", + language=self.language_to_service_language(Language.EN), + prompt=None, + temperature=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", GroqSTTSettings, "model") + default_settings.model = model + if language is not None: + _warn_deprecated_param("language", GroqSTTSettings, "language") + default_settings.language = self.language_to_service_language(language) + if prompt is not None: + _warn_deprecated_param("prompt", GroqSTTSettings, "prompt") + default_settings.prompt = prompt + if temperature is not None: + _warn_deprecated_param("temperature", GroqSTTSettings, "temperature") + default_settings.temperature = temperature + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - model=model, api_key=api_key, base_url=base_url, - language=language, - prompt=prompt, - temperature=temperature, + settings=default_settings, ttfs_p99_latency=ttfs_p99_latency, **kwargs, ) async def _transcribe(self, audio: bytes) -> Transcription: - assert self._language is not None # Assigned in the BaseWhisperSTTService class + assert self._settings.language is not None # Build kwargs dict with only set parameters kwargs = { @@ -65,13 +128,13 @@ class GroqSTTService(BaseWhisperSTTService): "model": self._settings.model, # Use verbose_json to get probability metrics "response_format": "verbose_json" if self._include_prob_metrics else "json", - "language": self._language, + "language": self._settings.language, } - if self._prompt is not None: - kwargs["prompt"] = self._prompt + if self._settings.prompt is not None: + kwargs["prompt"] = self._settings.prompt - if self._temperature is not None: - kwargs["temperature"] = self._temperature + if self._settings.temperature is not None: + kwargs["temperature"] = self._settings.temperature return await self._client.audio.transcriptions.create(**kwargs) diff --git a/src/pipecat/services/groq/tts.py b/src/pipecat/services/groq/tts.py index 901b786c0..18b623fc8 100644 --- a/src/pipecat/services/groq/tts.py +++ b/src/pipecat/services/groq/tts.py @@ -9,7 +9,7 @@ import io import wave from dataclasses import dataclass, field -from typing import AsyncGenerator, ClassVar, Dict, Optional +from typing import AsyncGenerator, Optional from loguru import logger from pydantic import BaseModel @@ -21,7 +21,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -39,16 +39,10 @@ class GroqTTSSettings(TTSSettings): """Settings for the Groq TTS service. Parameters: - output_format: Audio output format. speed: Speech speed multiplier. Defaults to 1.0. - groq_sample_rate: Audio sample rate. """ - output_format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speed: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - groq_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - - _aliases: ClassVar[Dict[str, str]] = {"voice_id": "voice", "sample_rate": "groq_sample_rate"} class GroqTTSService(TTSService): @@ -64,6 +58,9 @@ class GroqTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Groq TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=GroqTTSSettings(...)`` instead. + Parameters: language: Language for speech synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -80,9 +77,10 @@ class GroqTTSService(TTSService): api_key: str, output_format: str = "wav", params: Optional[InputParams] = None, - model_name: str = "canopylabs/orpheus-v1-english", - voice_id: str = "autumn", + model_name: Optional[str] = None, + voice_id: Optional[str] = None, sample_rate: Optional[int] = GROQ_SAMPLE_RATE, + settings: Optional[GroqTTSSettings] = None, **kwargs, ): """Initialize Groq TTS service. @@ -91,27 +89,59 @@ class GroqTTSService(TTSService): api_key: Groq API key for authentication. output_format: Audio output format. Defaults to "wav". params: Additional input parameters for voice customization. - model_name: TTS model to use. Defaults to "playai-tts". - voice_id: Voice identifier to use. Defaults to "Celeste-PlayAI". + + .. deprecated:: 0.0.105 + Use ``settings=GroqTTSSettings(...)`` instead. + + model_name: TTS model to use. + + .. deprecated:: 0.0.105 + Use ``settings=GroqTTSSettings(model=...)`` instead. + + voice_id: Voice identifier to use. + + .. deprecated:: 0.0.105 + Use ``settings=GroqTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. Must be 48000 Hz for Groq TTS. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ if sample_rate != self.GROQ_SAMPLE_RATE: logger.warning(f"Groq TTS only supports {self.GROQ_SAMPLE_RATE}Hz sample rate. ") - params = params or GroqTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = GroqTTSSettings( + model="canopylabs/orpheus-v1-english", + voice="autumn", + language="en", + speed=1.0, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model_name is not None: + _warn_deprecated_param("model_name", GroqTTSSettings, "model") + default_settings.model = model_name + if voice_id is not None: + _warn_deprecated_param("voice_id", GroqTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", GroqTTSSettings) + if not settings: + default_settings.language = str(params.language) if params.language else "en" + default_settings.speed = params.speed + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( pause_frame_processing=True, sample_rate=sample_rate, - settings=GroqTTSSettings( - model=model_name, - voice=voice_id, - language=str(params.language) if params.language else "en", - output_format=output_format, - speed=params.speed, - groq_sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/heygen/video.py b/src/pipecat/services/heygen/video.py index 7f3624f35..18df8ac60 100644 --- a/src/pipecat/services/heygen/video.py +++ b/src/pipecat/services/heygen/video.py @@ -12,6 +12,7 @@ audio/video streaming capabilities through the HeyGen API. """ import asyncio +from dataclasses import dataclass from typing import Optional, Union import aiohttp @@ -45,12 +46,20 @@ from pipecat.services.heygen.client import ( HeyGenClient, ServiceType, ) +from pipecat.services.settings import ServiceSettings from pipecat.transports.base_transport import TransportParams # Using the same values that we do in the BaseOutputTransport AVATAR_VAD_STOP_SECS = 0.35 +@dataclass +class HeyGenVideoSettings(ServiceSettings): + """Settings for the HeyGen video service.""" + + pass + + class HeyGenVideoService(AIService): """A service that integrates HeyGen's interactive avatar capabilities into the pipeline. @@ -80,6 +89,7 @@ class HeyGenVideoService(AIService): session: aiohttp.ClientSession, session_request: Optional[Union[LiveAvatarNewSessionRequest, NewSessionRequest]] = None, service_type: Optional[ServiceType] = None, + settings: Optional[HeyGenVideoSettings] = None, **kwargs, ) -> None: """Initialize the HeyGen video service. @@ -89,9 +99,15 @@ class HeyGenVideoService(AIService): session: HTTP client session for API requests session_request: Configuration for the HeyGen session service_type: Service type for the avatar session + settings: Runtime-updatable settings. HeyGen has no model concept, so this + is primarily used for the ``extra`` dict. **kwargs: Additional arguments passed to parent AIService """ - super().__init__(**kwargs) + default_settings = ServiceSettings(model=None) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._api_key = api_key self._session = session self._client: Optional[HeyGenClient] = None diff --git a/src/pipecat/services/hume/tts.py b/src/pipecat/services/hume/tts.py index 2a075ab36..052d1cd0a 100644 --- a/src/pipecat/services/hume/tts.py +++ b/src/pipecat/services/hume/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -84,6 +84,9 @@ class HumeTTSService(TTSService): class InputParams(BaseModel): """Optional synthesis parameters for Hume TTS. + .. deprecated:: 0.0.105 + Use ``settings=HumeTTSSettings(...)`` instead. + Parameters: description: Natural-language acting directions (up to 100 characters). speed: Speaking-rate multiplier (0.5-2.0). @@ -98,9 +101,10 @@ class HumeTTSService(TTSService): self, *, api_key: Optional[str] = None, - voice_id: str, + voice_id: Optional[str] = None, params: Optional[InputParams] = None, sample_rate: Optional[int] = HUME_SAMPLE_RATE, + settings: Optional[HumeTTSSettings] = None, **kwargs, ) -> None: """Initialize the HumeTTSService. @@ -108,8 +112,18 @@ class HumeTTSService(TTSService): Args: api_key: Hume API key. If omitted, reads the ``HUME_API_KEY`` environment variable. voice_id: ID of the voice to use. Only voice IDs are supported; voice names are not. + + .. deprecated:: 0.0.105 + Use ``settings=HumeTTSSettings(voice=...)`` instead. + params: Optional synthesis controls (acting instructions, speed, trailing silence). + + .. deprecated:: 0.0.105 + Use ``settings=HumeTTSSettings(...)`` instead. + sample_rate: Output sample rate for emitted PCM frames. Defaults to 48_000 (Hume). + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ api_key = api_key or os.getenv("HUME_API_KEY") @@ -121,21 +135,39 @@ class HumeTTSService(TTSService): f"Hume TTS streams at {HUME_SAMPLE_RATE} Hz; configured sample_rate={sample_rate}" ) - params = params or HumeTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = HumeTTSSettings( + model=None, + voice=None, + language=None, # Not applicable here + description=None, + speed=None, + trailing_silence=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", HumeTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", HumeTTSSettings) + if not settings: + default_settings.description = params.description + default_settings.speed = params.speed + default_settings.trailing_silence = params.trailing_silence + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, push_text_frames=False, push_stop_frames=True, supports_word_timestamps=True, - settings=HumeTTSSettings( - model=None, - voice=voice_id, - language=None, # Not applicable here - description=params.description, - speed=params.speed, - trailing_silence=params.trailing_silence, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/inworld/tts.py b/src/pipecat/services/inworld/tts.py index d3f64c16f..a1421b2ab 100644 --- a/src/pipecat/services/inworld/tts.py +++ b/src/pipecat/services/inworld/tts.py @@ -18,7 +18,18 @@ import base64 import json import uuid from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, ClassVar, Dict, List, Literal, Mapping, Optional, Tuple +from typing import ( + Any, + AsyncGenerator, + ClassVar, + Dict, + List, + Literal, + Mapping, + Optional, + Self, + Tuple, +) import aiohttp import websockets @@ -29,7 +40,7 @@ from pipecat import version as pipecat_version USER_AGENT = f"pipecat/{pipecat_version()}" from pydantic import BaseModel -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param try: from websockets.asyncio.client import connect as websocket_connect @@ -60,8 +71,6 @@ class InworldTTSSettings(TTSSettings): """Settings for Inworld TTS services. Parameters: - audio_encoding: Audio encoding format (e.g. LINEAR16). - audio_sample_rate: Audio sample rate in Hz. speaking_rate: Speaking rate for speech synthesis. temperature: Temperature for speech synthesis. auto_mode: Whether to use auto mode. Recommended when texts are sent @@ -73,8 +82,6 @@ class InworldTTSSettings(TTSSettings): timestamp_transport_strategy: Strategy for timestamp transport ("ASYNC" or "SYNC"). """ - audio_encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - audio_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speaking_rate: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) temperature: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) auto_mode: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -82,7 +89,6 @@ class InworldTTSSettings(TTSSettings): timestamp_transport_strategy: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) _aliases: ClassVar[Dict[str, str]] = { - "voice_id": "voice", "voiceId": "voice", "modelId": "model", "applyTextNormalization": "apply_text_normalization", @@ -91,13 +97,11 @@ class InworldTTSSettings(TTSSettings): } @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "InworldTTSSettings": + def from_mapping(cls, settings: Mapping[str, Any]) -> Self: """Construct settings from a plain dict, destructuring legacy nested ``audioConfig``.""" flat = dict(settings) nested = flat.pop("audioConfig", None) if isinstance(nested, dict): - flat.setdefault("audio_encoding", nested.get("audioEncoding")) - flat.setdefault("audio_sample_rate", nested.get("sampleRateHertz")) flat.setdefault("speaking_rate", nested.get("speakingRate")) return super().from_mapping(flat) @@ -114,6 +118,9 @@ class InworldHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Inworld TTS configuration. + .. deprecated:: 0.0.105 + Use ``InworldTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temperature: Temperature for speech synthesis. speaking_rate: Speaking rate for speech synthesis. @@ -129,12 +136,13 @@ class InworldHttpTTSService(TTSService): *, api_key: str, aiohttp_session: aiohttp.ClientSession, - voice_id: str = "Ashley", - model: str = "inworld-tts-1.5-max", + voice_id: Optional[str] = None, + model: Optional[str] = None, streaming: bool = True, sample_rate: Optional[int] = None, encoding: str = "LINEAR16", - params: InputParams = None, + params: Optional[InputParams] = None, + settings: Optional[InworldTTSSettings] = None, **kwargs, ): """Initialize the Inworld TTS service. @@ -143,32 +151,70 @@ class InworldHttpTTSService(TTSService): api_key: Inworld API key. aiohttp_session: aiohttp ClientSession for HTTP requests. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(voice=...)`` instead. + model: ID of the model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(model=...)`` instead. + streaming: Whether to use streaming mode. sample_rate: Audio sample rate in Hz. encoding: Audio encoding format. params: Input parameters for Inworld TTS configuration. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ - params = params or InworldHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = InworldTTSSettings( + model="inworld-tts-1.5-max", + voice="Ashley", + language=None, + speaking_rate=None, + temperature=None, + timestamp_transport_strategy="ASYNC", + auto_mode=None, # Not applicable for HTTP TTS + apply_text_normalization=None, # Not applicable for HTTP TTS + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", InworldTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", InworldTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", InworldTTSSettings) + if not settings: + if params.speaking_rate is not None: + default_settings.speaking_rate = params.speaking_rate + if params.temperature is not None: + default_settings.temperature = params.temperature + if params.timestamp_transport_strategy is not None: + default_settings.timestamp_transport_strategy = ( + params.timestamp_transport_strategy + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_text_frames=False, push_stop_frames=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=InworldTTSSettings( - model=model, - voice=voice_id, - language=None, - audio_encoding=encoding, - audio_sample_rate=0, - speaking_rate=params.speaking_rate, - temperature=params.temperature, - timestamp_transport_strategy=params.timestamp_transport_strategy, - auto_mode=None, # Not applicable for HTTP TTS - apply_text_normalization=None, # Not applicable for HTTP TTS - ), + settings=default_settings, **kwargs, ) @@ -184,6 +230,10 @@ class InworldHttpTTSService(TTSService): self._cumulative_time = 0.0 + # Init-only audio format config (not runtime-updatable). + self._audio_encoding = encoding + self._audio_sample_rate = 0 # Set in start() + def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -199,7 +249,7 @@ class InworldHttpTTSService(TTSService): frame: The start frame. """ await super().start(frame) - self._settings.audio_sample_rate = self.sample_rate + self._audio_sample_rate = self.sample_rate async def stop(self, frame: EndFrame): """Stop the Inworld TTS service. @@ -279,8 +329,8 @@ class InworldHttpTTSService(TTSService): logger.debug(f"{self}: Generating TTS [{text}] (streaming={self._streaming})") audio_config = { - "audioEncoding": self._settings.audio_encoding, - "sampleRateHertz": self._settings.audio_sample_rate, + "audioEncoding": self._audio_encoding, + "sampleRateHertz": self._audio_sample_rate, } if self._settings.speaking_rate is not None: audio_config["speakingRate"] = self._settings.speaking_rate @@ -477,6 +527,9 @@ class InworldTTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for Inworld WebSocket TTS configuration. + .. deprecated:: 0.0.105 + Use ``InworldTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temperature: Temperature for speech synthesis. speaking_rate: Speaking rate for speech synthesis. @@ -503,12 +556,13 @@ class InworldTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str = "Ashley", - model: str = "inworld-tts-1.5-max", + voice_id: Optional[str] = None, + model: Optional[str] = None, url: str = "wss://api.inworld.ai/tts/v1/voice:streamBidirectional", sample_rate: Optional[int] = None, encoding: str = "LINEAR16", - params: InputParams = None, + params: Optional[InputParams] = None, + settings: Optional[InworldTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, append_trailing_space: bool = True, @@ -519,11 +573,25 @@ class InworldTTSService(AudioContextTTSService): Args: api_key: Inworld API key. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(voice=...)`` instead. + model: ID of the model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(model=...)`` instead. + url: URL of the Inworld WebSocket API. sample_rate: Audio sample rate in Hz. encoding: Audio encoding format. params: Input parameters for Inworld WebSocket TTS configuration. + + .. deprecated:: 0.0.105 + Use ``settings=InworldTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -533,7 +601,50 @@ class InworldTTSService(AudioContextTTSService): append_trailing_space: Whether to append a trailing space to text before sending to TTS. **kwargs: Additional arguments passed to the parent class. """ - params = params or InworldTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = InworldTTSSettings( + model="inworld-tts-1.5-max", + voice="Ashley", + language=None, + speaking_rate=None, + temperature=None, + apply_text_normalization=None, + timestamp_transport_strategy="ASYNC", + auto_mode=True if aggregate_sentences is None else aggregate_sentences, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", InworldTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", InworldTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + _buffer_max_delay_ms = None + _buffer_char_threshold = None + if params is not None: + _warn_deprecated_param("params", InworldTTSSettings) + if not settings: + if params.speaking_rate is not None: + default_settings.speaking_rate = params.speaking_rate + if params.temperature is not None: + default_settings.temperature = params.temperature + if params.apply_text_normalization is not None: + default_settings.apply_text_normalization = params.apply_text_normalization + if params.timestamp_transport_strategy is not None: + default_settings.timestamp_transport_strategy = ( + params.timestamp_transport_strategy + ) + if params.auto_mode is not None: + default_settings.auto_mode = params.auto_mode + _buffer_max_delay_ms = params.max_buffer_delay_ms + _buffer_char_threshold = params.buffer_char_threshold + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_text_frames=False, @@ -544,18 +655,7 @@ class InworldTTSService(AudioContextTTSService): aggregate_sentences=aggregate_sentences, text_aggregation_mode=text_aggregation_mode, append_trailing_space=append_trailing_space, - settings=InworldTTSSettings( - model=model, - voice=voice_id, - language=None, - audio_encoding=encoding, - audio_sample_rate=0, - speaking_rate=params.speaking_rate, - temperature=params.temperature, - apply_text_normalization=params.apply_text_normalization, - timestamp_transport_strategy=params.timestamp_transport_strategy, - auto_mode=params.auto_mode if params.auto_mode is not None else aggregate_sentences, - ), + settings=default_settings, **kwargs, ) @@ -564,8 +664,8 @@ class InworldTTSService(AudioContextTTSService): self._timestamp_type = "WORD" self._buffer_settings = { - "maxBufferDelayMs": params.max_buffer_delay_ms, - "bufferCharThreshold": params.buffer_char_threshold, + "maxBufferDelayMs": _buffer_max_delay_ms, + "bufferCharThreshold": _buffer_char_threshold, } self._receive_task = None @@ -579,6 +679,10 @@ class InworldTTSService(AudioContextTTSService): # Track the end time of the last word in the current generation self._generation_end_time = 0.0 + # Init-only audio format config (not runtime-updatable). + self._audio_encoding = encoding + self._audio_sample_rate = 0 # Set in start() + def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -594,7 +698,7 @@ class InworldTTSService(AudioContextTTSService): frame: The start frame. """ await super().start(frame) - self._settings.audio_sample_rate = self.sample_rate + self._audio_sample_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -944,8 +1048,8 @@ class InworldTTSService(AudioContextTTSService): context_id: The context ID. """ audio_config = { - "audioEncoding": self._settings.audio_encoding, - "sampleRateHertz": self._settings.audio_sample_rate, + "audioEncoding": self._audio_encoding, + "sampleRateHertz": self._audio_sample_rate, } if self._settings.speaking_rate is not None: audio_config["speakingRate"] = self._settings.speaking_rate diff --git a/src/pipecat/services/kokoro/tts.py b/src/pipecat/services/kokoro/tts.py index 4b35fa46d..0646923f3 100644 --- a/src/pipecat/services/kokoro/tts.py +++ b/src/pipecat/services/kokoro/tts.py @@ -7,7 +7,7 @@ """Kokoro TTS service implementation using kokoro-onnx.""" import os -from dataclasses import dataclass, field +from dataclasses import dataclass from pathlib import Path from typing import AsyncGenerator, Optional @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -91,13 +91,9 @@ def language_to_kokoro_language(language: Language) -> str: @dataclass class KokoroTTSSettings(TTSSettings): - """Settings for the Kokoro TTS service. + """Settings for the Kokoro TTS service.""" - Parameters: - lang_code: Kokoro language code for synthesis. - """ - - lang_code: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class KokoroTTSService(TTSService): @@ -112,6 +108,9 @@ class KokoroTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Kokoro TTS configuration. + .. deprecated:: 0.0.105 + Use ``KokoroTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -121,42 +120,66 @@ class KokoroTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, model_path: Optional[str] = None, voices_path: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[KokoroTTSSettings] = None, **kwargs, ): """Initialize the Kokoro TTS service. Args: voice_id: Voice identifier to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=KokoroTTSSettings(voice=...)`` instead. + model_path: Path to the kokoro ONNX model file. Defaults to auto-downloaded file. voices_path: Path to the voices binary file. Defaults to auto-downloaded file. params: Configuration parameters for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=KokoroTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent `TTSService`. """ - params = params or KokoroTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = KokoroTTSSettings( + model=None, + voice=None, + language=language_to_kokoro_language(Language.EN), + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", KokoroTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", KokoroTTSSettings) + if not settings: + default_settings.language = language_to_kokoro_language(params.language) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=KokoroTTSSettings( - model=None, - voice=voice_id, - language=language_to_kokoro_language(params.language), - lang_code=language_to_kokoro_language(params.language), - ), + settings=default_settings, **kwargs, ) - self._lang_code = language_to_kokoro_language(params.language) - - model = Path(model_path) if model_path else KOKORO_CACHE_DIR / "kokoro-v1.0.onnx" + model_file = Path(model_path) if model_path else KOKORO_CACHE_DIR / "kokoro-v1.0.onnx" voices = Path(voices_path) if voices_path else KOKORO_CACHE_DIR / "voices-v1.0.bin" - _ensure_model_files(model, voices) + _ensure_model_files(model_file, voices) - self._kokoro = Kokoro(str(model), str(voices)) + self._kokoro = Kokoro(str(model_file), str(voices)) self._resampler = create_stream_resampler() @@ -164,6 +187,17 @@ class KokoroTTSService(TTSService): """Indicate that this service supports TTFB and usage metrics.""" return True + def language_to_service_language(self, language: Language) -> str: + """Convert a Language enum to kokoro-onnx language format. + + Args: + language: The language to convert. + + Returns: + The kokoro-onnx language code. + """ + return language_to_kokoro_language(language) + @traced_tts async def run_tts(self, text: str, context_id: str) -> AsyncGenerator[Frame, None]: """Synthesize speech from text using kokoro-onnx. @@ -183,7 +217,7 @@ class KokoroTTSService(TTSService): yield TTSStartedFrame(context_id=context_id) stream = self._kokoro.create_stream( - text, voice=self._settings.voice, lang=self._lang_code, speed=1.0 + text, voice=self._settings.voice, lang=self._settings.language, speed=1.0 ) async for samples, sample_rate in stream: diff --git a/src/pipecat/services/lmnt/tts.py b/src/pipecat/services/lmnt/tts.py index a2c500ca2..9ee6d8d60 100644 --- a/src/pipecat/services/lmnt/tts.py +++ b/src/pipecat/services/lmnt/tts.py @@ -7,7 +7,7 @@ """LMNT text-to-speech service implementation.""" import json -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -17,14 +17,13 @@ from pipecat.frames.frames import ( EndFrame, ErrorFrame, Frame, - InterruptionFrame, StartFrame, TTSAudioRawFrame, TTSStartedFrame, TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -75,13 +74,9 @@ def language_to_lmnt_language(language: Language) -> Optional[str]: @dataclass class LmntTTSSettings(TTSSettings): - """Settings for LMNT TTS service. + """Settings for LMNT TTS service.""" - Parameters: - format: Audio output format. Defaults to "raw". - """ - - format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class LmntTTSService(InterruptibleTTSService): @@ -98,10 +93,11 @@ class LmntTTSService(InterruptibleTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, language: Language = Language.EN, - model: str = "blizzard", + model: Optional[str] = None, + settings: Optional[LmntTTSSettings] = None, **kwargs, ): """Initialize the LMNT TTS service. @@ -109,25 +105,52 @@ class LmntTTSService(InterruptibleTTSService): Args: api_key: LMNT API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=LmntTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses default. language: Language for synthesis. Defaults to English. - model: TTS model to use. Defaults to "blizzard". + model: TTS model to use. + + .. deprecated:: 0.0.105 + Use ``settings=LmntTTSSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = LmntTTSSettings( + model="blizzard", + voice=None, + language=self.language_to_service_language(language), + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", LmntTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", LmntTTSSettings, "model") + default_settings.model = model + + # 3. No params for this service + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( push_stop_frames=True, pause_frame_processing=True, sample_rate=sample_rate, - settings=LmntTTSSettings( - model=model, - voice=voice_id, - language=self.language_to_service_language(language), - format="raw", - ), + settings=default_settings, **kwargs, ) self._api_key = api_key + self._output_format = "raw" self._receive_task = None self._context_id: Optional[str] = None @@ -234,7 +257,7 @@ class LmntTTSService(InterruptibleTTSService): init_msg = { "X-API-Key": self._api_key, "voice": self._settings.voice, - "format": self._settings.format, + "format": self._output_format, "sample_rate": self.sample_rate, "language": self._settings.language, "model": self._settings.model, diff --git a/src/pipecat/services/minimax/tts.py b/src/pipecat/services/minimax/tts.py index 116d24a34..efe8c1fd9 100644 --- a/src/pipecat/services/minimax/tts.py +++ b/src/pipecat/services/minimax/tts.py @@ -12,7 +12,7 @@ for streaming text-to-speech synthesis. import json from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, ClassVar, Dict, Mapping, Optional +from typing import Any, AsyncGenerator, Mapping, Optional, Self import aiohttp from loguru import logger @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -100,10 +100,6 @@ class MiniMaxTTSSettings(TTSSettings): "disgusted", "surprised", "calm", "fluent"). text_normalization: Enable text normalization (Chinese/English). latex_read: Enable LaTeX formula reading. - audio_bitrate: Audio bitrate in bps. - audio_format: Audio output format. - audio_channel: Number of audio channels. - audio_sample_rate: Audio sample rate in Hz. language_boost: Language boost string for multilingual support. """ @@ -114,16 +110,10 @@ class MiniMaxTTSSettings(TTSSettings): emotion: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) text_normalization: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) latex_read: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - audio_bitrate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - audio_format: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - audio_channel: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - audio_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) language_boost: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - _aliases: ClassVar[Dict[str, str]] = {"voice_id": "voice"} - @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "MiniMaxTTSSettings": + def from_mapping(cls, settings: Mapping[str, Any]) -> Self: """Construct settings from a plain dict, destructuring legacy nested dicts. Handles ``voice_setting`` (with ``vol`` → ``volume`` rename) and @@ -140,13 +130,6 @@ class MiniMaxTTSSettings(TTSSettings): flat.setdefault("text_normalization", voice.get("text_normalization")) flat.setdefault("latex_read", voice.get("latex_read")) - audio = flat.pop("audio_setting", None) - if isinstance(audio, dict): - flat.setdefault("audio_bitrate", audio.get("bitrate")) - flat.setdefault("audio_format", audio.get("format")) - flat.setdefault("audio_channel", audio.get("channel")) - flat.setdefault("audio_sample_rate", audio.get("sample_rate")) - return super().from_mapping(flat) @@ -166,6 +149,9 @@ class MiniMaxHttpTTSService(TTSService): class InputParams(BaseModel): """Configuration parameters for MiniMax TTS. + .. deprecated:: 0.0.105 + Use ``MiniMaxTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for TTS generation. Supports 40 languages. Note: Filipino, Tamil, and Persian require speech-2.6-* models. @@ -201,11 +187,12 @@ class MiniMaxHttpTTSService(TTSService): api_key: str, base_url: str = "https://api.minimax.io/v1/t2a_v2", group_id: str, - model: str = "speech-02-turbo", - voice_id: str = "Calm_Woman", + model: Optional[str] = None, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[MiniMaxTTSSettings] = None, **kwargs, ): """Initialize the MiniMax TTS service. @@ -221,33 +208,104 @@ class MiniMaxHttpTTSService(TTSService): "speech-2.6-hd", "speech-2.6-turbo" (latest, supports Filipino/Tamil/Persian), "speech-02-hd", "speech-02-turbo", "speech-01-hd", "speech-01-turbo". + + .. deprecated:: 0.0.105 + Use ``settings=MiniMaxTTSSettings(model=...)`` instead. + voice_id: Voice identifier. Defaults to "Calm_Woman". + + .. deprecated:: 0.0.105 + Use ``settings=MiniMaxTTSSettings(voice=...)`` instead. + aiohttp_session: aiohttp.ClientSession for API communication. sample_rate: Output audio sample rate in Hz. If None, uses pipeline default. params: Additional configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=MiniMaxTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or MiniMaxHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = MiniMaxTTSSettings( + model="speech-02-turbo", + voice="Calm_Woman", + language=None, + stream=True, + speed=1.0, + volume=1.0, + pitch=0, + language_boost=None, + emotion=None, + text_normalization=None, + latex_read=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", MiniMaxTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", MiniMaxTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", MiniMaxTTSSettings) + if not settings: + default_settings.speed = params.speed + default_settings.volume = params.volume + default_settings.pitch = params.pitch + default_settings.latex_read = params.latex_read + + # Resolve language boost + if params.language: + service_lang = self.language_to_service_language(params.language) + if service_lang: + default_settings.language_boost = service_lang + + # Resolve emotion + if params.emotion: + supported_emotions = [ + "happy", + "sad", + "angry", + "fearful", + "disgusted", + "surprised", + "neutral", + "fluent", + ] + if params.emotion in supported_emotions: + default_settings.emotion = params.emotion + else: + logger.warning( + f"Unsupported emotion: {params.emotion}. Supported emotions: {supported_emotions}" + ) + + # Resolve text_normalization + if params.english_normalization is not None: + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn( + "Parameter `english_normalization` is deprecated and will be removed in a future version. Use `text_normalization` instead.", + DeprecationWarning, + ) + default_settings.text_normalization = params.english_normalization + if params.text_normalization is not None: + default_settings.text_normalization = params.text_normalization + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=MiniMaxTTSSettings( - model=model, - voice=voice_id, - language=None, - stream=True, - speed=params.speed, - volume=params.volume, - pitch=params.pitch, - language_boost=None, - emotion=None, - text_normalization=None, - latex_read=None, - audio_bitrate=128000, - audio_format="pcm", - audio_channel=1, - audio_sample_rate=0, - ), + settings=default_settings, **kwargs, ) @@ -256,51 +314,11 @@ class MiniMaxHttpTTSService(TTSService): self._base_url = f"{base_url}?GroupId={group_id}" self._session = aiohttp_session - # Add language boost if provided - if params.language: - service_lang = self.language_to_service_language(params.language) - if service_lang: - self._settings.language_boost = service_lang - - # Add optional emotion if provided - if params.emotion: - # Validate emotion is in the supported list - supported_emotions = [ - "happy", - "sad", - "angry", - "fearful", - "disgusted", - "surprised", - "neutral", - "fluent", - ] - if params.emotion in supported_emotions: - self._settings.emotion = params.emotion - else: - logger.warning( - f"Unsupported emotion: {params.emotion}. Supported emotions: {supported_emotions}" - ) - - # If `english_normalization`, add `text_normalization` and print warning - if params.english_normalization is not None: - import warnings - - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "Parameter `english_normalization` is deprecated and will be removed in a future version. Use `text_normalization` instead.", - DeprecationWarning, - ) - self._settings.text_normalization = params.english_normalization - - # Add text_normalization if provided (corrected parameter name) - if params.text_normalization is not None: - self._settings.text_normalization = params.text_normalization - - # Add latex_read if provided - if params.latex_read is not None: - self._settings.latex_read = params.latex_read + # Init-only audio format config + self._audio_bitrate = 128000 + self._audio_format = "pcm" + self._audio_channel = 1 + self._audio_sample_rate = 0 # Set in start() def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -328,7 +346,7 @@ class MiniMaxHttpTTSService(TTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.audio_sample_rate = self.sample_rate + self._audio_sample_rate = self.sample_rate logger.debug(f"MiniMax TTS initialized with sample_rate: {self.sample_rate}") @traced_tts @@ -366,10 +384,10 @@ class MiniMaxHttpTTSService(TTSService): # Build audio_setting dict for API audio_setting = { - "bitrate": self._settings.audio_bitrate, - "format": self._settings.audio_format, - "channel": self._settings.audio_channel, - "sample_rate": self._settings.audio_sample_rate, + "bitrate": self._audio_bitrate, + "format": self._audio_format, + "channel": self._audio_channel, + "sample_rate": self._audio_sample_rate, } # Create payload from settings diff --git a/src/pipecat/services/mistral/llm.py b/src/pipecat/services/mistral/llm.py index 984ffb7dd..647a56bca 100644 --- a/src/pipecat/services/mistral/llm.py +++ b/src/pipecat/services/mistral/llm.py @@ -6,14 +6,24 @@ """Mistral LLM service implementation using OpenAI-compatible interface.""" -from typing import List, Sequence +from dataclasses import dataclass +from typing import List, Optional, Sequence from loguru import logger from openai.types.chat import ChatCompletionMessageParam from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams from pipecat.frames.frames import FunctionCallFromLLM +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class MistralLLMSettings(OpenAILLMSettings): + """Settings for Mistral LLM service.""" + + pass class MistralLLMService(OpenAILLMService): @@ -23,12 +33,15 @@ class MistralLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: MistralLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.mistral.ai/v1", - model: str = "mistral-small-latest", + model: Optional[str] = None, + settings: Optional[MistralLLMSettings] = None, **kwargs, ): """Initialize the Mistral LLM service. @@ -37,9 +50,27 @@ class MistralLLMService(OpenAILLMService): api_key: The API key for accessing Mistral's API. base_url: The base URL for Mistral API. Defaults to "https://api.mistral.ai/v1". model: The model identifier to use. Defaults to "mistral-small-latest". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = MistralLLMSettings(model="mistral-small-latest") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", MistralLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Mistral API endpoint. @@ -200,4 +231,11 @@ class MistralLLMService(OpenAILLMService): # Add any extra parameters params.update(self._settings.extra) + # Prepend system instruction if set + if self._settings.system_instruction: + messages = params.get("messages", []) + params["messages"] = [ + {"role": "system", "content": self._settings.system_instruction} + ] + messages + return params diff --git a/src/pipecat/services/moondream/vision.py b/src/pipecat/services/moondream/vision.py index 53b98b77a..32b592061 100644 --- a/src/pipecat/services/moondream/vision.py +++ b/src/pipecat/services/moondream/vision.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( VisionFullResponseStartFrame, VisionTextFrame, ) -from pipecat.services.settings import VisionSettings +from pipecat.services.settings import VisionSettings, _warn_deprecated_param from pipecat.services.vision_service import VisionService try: @@ -80,17 +80,41 @@ class MoondreamService(VisionService): """ def __init__( - self, *, model="vikhyatk/moondream2", revision="2025-01-09", use_cpu=False, **kwargs + self, + *, + model: Optional[str] = None, + revision="2025-01-09", + use_cpu=False, + settings: Optional[MoondreamSettings] = None, + **kwargs, ): """Initialize the Moondream service. Args: model: Hugging Face model identifier for the Moondream model. + + .. deprecated:: 0.0.105 + Use ``settings=MoondreamSettings(model=...)`` instead. + revision: Specific model revision to use. use_cpu: Whether to force CPU usage instead of hardware acceleration. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent VisionService. """ - super().__init__(settings=MoondreamSettings(model=model), **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = MoondreamSettings(model="vikhyatk/moondream2") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", MoondreamSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) if not use_cpu: device, dtype = detect_device() @@ -101,7 +125,7 @@ class MoondreamService(VisionService): logger.debug("Loading Moondream model...") self._model = AutoModelForCausalLM.from_pretrained( - model, + self._settings.model, trust_remote_code=True, revision=revision, device_map={"": device}, diff --git a/src/pipecat/services/neuphonic/tts.py b/src/pipecat/services/neuphonic/tts.py index 63411c3eb..da14ec2e5 100644 --- a/src/pipecat/services/neuphonic/tts.py +++ b/src/pipecat/services/neuphonic/tts.py @@ -35,7 +35,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -80,13 +80,9 @@ class NeuphonicTTSSettings(TTSSettings): Parameters: speed: Speech speed multiplier. Defaults to 1.0. - encoding: Audio encoding format. - sampling_rate: Audio sample rate. """ speed: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - encoding: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - sampling_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class NeuphonicTTSService(InterruptibleTTSService): @@ -102,6 +98,9 @@ class NeuphonicTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Input parameters for Neuphonic TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -119,6 +118,7 @@ class NeuphonicTTSService(InterruptibleTTSService): sample_rate: Optional[int] = 22050, encoding: str = "pcm_linear", params: Optional[InputParams] = None, + settings: Optional[NeuphonicTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -128,10 +128,20 @@ class NeuphonicTTSService(InterruptibleTTSService): Args: api_key: Neuphonic API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(voice=...)`` instead. + url: WebSocket URL for the Neuphonic API. sample_rate: Audio sample rate in Hz. Defaults to 22050. encoding: Audio encoding format. Defaults to "pcm_linear". params: Additional input parameters for TTS configuration. + + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -140,7 +150,31 @@ class NeuphonicTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ - params = params or NeuphonicTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = NeuphonicTTSSettings( + model=None, + voice=None, + language=self.language_to_service_language(Language.EN), + speed=1.0, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", NeuphonicTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", NeuphonicTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = self.language_to_service_language(params.language) + if params.speed is not None: + default_settings.speed = params.speed + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -148,14 +182,7 @@ class NeuphonicTTSService(InterruptibleTTSService): push_stop_frames=True, stop_frame_timeout_s=2.0, sample_rate=sample_rate, - settings=NeuphonicTTSSettings( - model=None, - language=self.language_to_service_language(params.language), - speed=params.speed, - encoding=encoding, - sampling_rate=sample_rate, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -167,6 +194,8 @@ class NeuphonicTTSService(InterruptibleTTSService): self._receive_task = None self._keepalive_task = None self._context_id: Optional[str] = None + self._encoding = encoding + self._sampling_rate = sample_rate def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -294,8 +323,8 @@ class NeuphonicTTSService(InterruptibleTTSService): tts_config = { "lang_code": self._settings.language, "speed": self._settings.speed, - "encoding": self._settings.encoding, - "sampling_rate": self._settings.sampling_rate, + "encoding": self._encoding, + "sampling_rate": self._sampling_rate, "voice_id": self._settings.voice, } @@ -418,6 +447,9 @@ class NeuphonicHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Neuphonic HTTP TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -436,6 +468,7 @@ class NeuphonicHttpTTSService(TTSService): sample_rate: Optional[int] = 22050, encoding: Optional[str] = "pcm_linear", params: Optional[InputParams] = None, + settings: Optional[NeuphonicTTSSettings] = None, **kwargs, ): """Initialize the Neuphonic HTTP TTS service. @@ -443,31 +476,61 @@ class NeuphonicHttpTTSService(TTSService): Args: api_key: Neuphonic API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. url: Base URL for the Neuphonic HTTP API. sample_rate: Audio sample rate in Hz. Defaults to 22050. encoding: Audio encoding format. Defaults to "pcm_linear". params: Additional input parameters for TTS configuration. + + .. deprecated:: 0.0.105 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or NeuphonicHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = NeuphonicTTSSettings( + model=None, + voice=None, + language=self.language_to_service_language(Language.EN) or "en", + speed=1.0, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", NeuphonicTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", NeuphonicTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = ( + self.language_to_service_language(params.language) or "en" + ) + if params.speed is not None: + default_settings.speed = params.speed + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=NeuphonicTTSSettings( - model=None, - voice=voice_id, - language=self.language_to_service_language(params.language) or "en", - speed=params.speed, - encoding=encoding, - sampling_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._session = aiohttp_session self._base_url = url.rstrip("/") + self._encoding = encoding def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -561,7 +624,7 @@ class NeuphonicHttpTTSService(TTSService): payload = { "text": text, "lang_code": self._settings.language, - "encoding": self._settings.encoding, + "encoding": self._encoding, "sampling_rate": self.sample_rate, "speed": self._settings.speed, } diff --git a/src/pipecat/services/nvidia/llm.py b/src/pipecat/services/nvidia/llm.py index c5db58f31..48ccbaaf4 100644 --- a/src/pipecat/services/nvidia/llm.py +++ b/src/pipecat/services/nvidia/llm.py @@ -10,10 +10,22 @@ This module provides a service for interacting with NVIDIA's NIM (NVIDIA Inferen Microservice) API while maintaining compatibility with the OpenAI-style interface. """ +from dataclasses import dataclass +from typing import Optional + from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class NvidiaLLMSettings(OpenAILLMSettings): + """Settings for NVIDIA LLM service.""" + + pass class NvidiaLLMService(OpenAILLMService): @@ -24,12 +36,15 @@ class NvidiaLLMService(OpenAILLMService): in token usage reporting between NIM (incremental) and OpenAI (final summary). """ + _settings: NvidiaLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://integrate.api.nvidia.com/v1", - model: str = "nvidia/llama-3.1-nemotron-70b-instruct", + model: Optional[str] = None, + settings: Optional[NvidiaLLMSettings] = None, **kwargs, ): """Initialize the NvidiaLLMService. @@ -37,10 +52,29 @@ class NvidiaLLMService(OpenAILLMService): Args: api_key: The API key for accessing NVIDIA's NIM API. base_url: The base URL for NIM API. Defaults to "https://integrate.api.nvidia.com/v1". - model: The model identifier to use. Defaults to "nvidia/llama-3.1-nemotron-70b-instruct". + model: The model identifier to use. Defaults to + "nvidia/llama-3.1-nemotron-70b-instruct". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = NvidiaLLMSettings(model="nvidia/llama-3.1-nemotron-70b-instruct") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", NvidiaLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Counters for accumulating token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 diff --git a/src/pipecat/services/nvidia/stt.py b/src/pipecat/services/nvidia/stt.py index 950515096..6823965a9 100644 --- a/src/pipecat/services/nvidia/stt.py +++ b/src/pipecat/services/nvidia/stt.py @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( StartFrame, TranscriptionFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import NVIDIA_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService, STTService from pipecat.transcriptions.language import Language, resolve_language @@ -113,7 +113,7 @@ class NvidiaSegmentedSTTSettings(STTSettings): profanity_filter: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) automatic_punctuation: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) verbatim_transcripts: bool | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - boosted_lm_words: List[str] | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + boosted_lm_words: List[str] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) boosted_lm_score: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -130,6 +130,9 @@ class NvidiaSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for NVIDIA Riva STT service. + .. deprecated:: 0.0.105 + Use ``settings=NvidiaSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. Defaults to EN_US. """ @@ -148,6 +151,7 @@ class NvidiaSTTService(STTService): sample_rate: Optional[int] = None, params: Optional[InputParams] = None, use_ssl: bool = True, + settings: Optional[NvidiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = NVIDIA_TTFS_P99, **kwargs, ): @@ -159,20 +163,39 @@ class NvidiaSTTService(STTService): model_function_map: Mapping containing 'function_id' and 'model_name' for the ASR model. sample_rate: Audio sample rate in Hz. If None, uses pipeline default. params: Additional configuration parameters for NVIDIA Riva. + + .. deprecated:: 0.0.105 + Use ``settings=NvidiaSTTSettings(...)`` instead. + use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - params = params or NvidiaSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = NvidiaSTTSettings( + model=model_function_map.get("model_name"), + language=Language.EN_US, + ) + + # 2. (no deprecated direct args for this service) + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", NvidiaSTTSettings) + if not settings: + default_settings.language = params.language + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=NvidiaSTTSettings( - model=model_function_map.get("model_name"), - language=params.language, - ), + settings=default_settings, **kwargs, ) @@ -421,6 +444,9 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for NVIDIA Riva segmented STT service. + .. deprecated:: 0.0.105 + Use ``settings=NvidiaSegmentedSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. Defaults to EN_US. profanity_filter: Whether to filter profanity from results. @@ -449,6 +475,7 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): sample_rate: Optional[int] = None, params: Optional[InputParams] = None, use_ssl: bool = True, + settings: Optional[NvidiaSegmentedSTTSettings] = None, ttfs_p99_latency: Optional[float] = NVIDIA_TTFS_P99, **kwargs, ): @@ -460,26 +487,51 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): model_function_map: Mapping of model name and its corresponding NVIDIA Cloud Function ID sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate params: Additional configuration parameters for NVIDIA Riva + + .. deprecated:: 0.0.105 + Use ``settings=NvidiaSegmentedSTTSettings(...)`` instead. + use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService """ - params = params or NvidiaSegmentedSTTService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = NvidiaSegmentedSTTSettings( + model=model_function_map.get("model_name"), + language=language_to_nvidia_riva_language(Language.EN_US) or "en-US", + profanity_filter=False, + automatic_punctuation=True, + verbatim_transcripts=False, + boosted_lm_words=None, + boosted_lm_score=4.0, + ) + + # 2. (no deprecated direct args for this service) + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", NvidiaSegmentedSTTSettings) + if not settings: + default_settings.language = ( + language_to_nvidia_riva_language(params.language or Language.EN_US) or "en-US" + ) + default_settings.profanity_filter = params.profanity_filter + default_settings.automatic_punctuation = params.automatic_punctuation + default_settings.verbatim_transcripts = params.verbatim_transcripts + default_settings.boosted_lm_words = params.boosted_lm_words + default_settings.boosted_lm_score = params.boosted_lm_score + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=NvidiaSegmentedSTTSettings( - model=model_function_map.get("model_name"), - language=self.language_to_service_language(params.language or Language.EN_US) - or "en-US", - profanity_filter=params.profanity_filter, - automatic_punctuation=params.automatic_punctuation, - verbatim_transcripts=params.verbatim_transcripts, - boosted_lm_words=params.boosted_lm_words, - boosted_lm_score=params.boosted_lm_score, - ), + settings=default_settings, **kwargs, ) @@ -534,19 +586,18 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): def _create_recognition_config(self): """Create the NVIDIA Riva ASR recognition configuration.""" # Create base configuration + s = self._settings config = riva.client.RecognitionConfig( language_code=self._get_language_code(), max_alternatives=1, - profanity_filter=self._settings.profanity_filter, - enable_automatic_punctuation=self._settings.automatic_punctuation, - verbatim_transcripts=self._settings.verbatim_transcripts, + profanity_filter=s.profanity_filter, + enable_automatic_punctuation=s.automatic_punctuation, + verbatim_transcripts=s.verbatim_transcripts, ) # Add word boosting if specified - if self._settings.boosted_lm_words: - riva.client.add_word_boosting_to_config( - config, self._settings.boosted_lm_words, self._settings.boosted_lm_score - ) + if s.boosted_lm_words: + riva.client.add_word_boosting_to_config(config, s.boosted_lm_words, s.boosted_lm_score) # Add voice activity detection parameters riva.client.add_endpoint_parameters_to_config( diff --git a/src/pipecat/services/nvidia/tts.py b/src/pipecat/services/nvidia/tts.py index 6785e9631..6e3298a75 100644 --- a/src/pipecat/services/nvidia/tts.py +++ b/src/pipecat/services/nvidia/tts.py @@ -31,7 +31,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language @@ -68,6 +68,9 @@ class NvidiaTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Riva TTS configuration. + .. deprecated:: 0.0.105 + Use ``NvidiaTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language code for synthesis. Defaults to US English. quality: Audio quality setting (0-100). Defaults to 20. @@ -81,13 +84,14 @@ class NvidiaTTSService(TTSService): *, api_key: str, server: str = "grpc.nvcf.nvidia.com:443", - voice_id: str = "Magpie-Multilingual.EN-US.Aria", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, model_function_map: Mapping[str, str] = { "function_id": "877104f7-e885-42b9-8de8-f6e4c6303969", "model_name": "magpie-tts-multilingual", }, params: Optional[InputParams] = None, + settings: Optional[NvidiaTTSSettings] = None, use_ssl: bool = True, **kwargs, ): @@ -96,23 +100,52 @@ class NvidiaTTSService(TTSService): Args: api_key: NVIDIA API key for authentication. server: gRPC server endpoint. Defaults to NVIDIA's cloud endpoint. - voice_id: Voice model identifier. Defaults to multilingual Ray voice. + voice_id: Voice model identifier. Defaults to multilingual Aria voice. + + .. deprecated:: 0.0.105 + Use ``settings=NvidiaTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses service default. model_function_map: Dictionary containing function_id and model_name for the TTS model. params: Additional configuration parameters for TTS synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=NvidiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or NvidiaTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = NvidiaTTSSettings( + model=model_function_map.get("model_name"), + voice="Magpie-Multilingual.EN-US.Aria", + language=Language.EN_US, + quality=20, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", NvidiaTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", NvidiaTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = params.language + if params.quality is not None: + default_settings.quality = params.quality + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=NvidiaTTSSettings( - model=model_function_map.get("model_name"), - voice=voice_id, - language=params.language, - quality=params.quality, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/ollama/llm.py b/src/pipecat/services/ollama/llm.py index 04f22bbae..d1c0eeebd 100644 --- a/src/pipecat/services/ollama/llm.py +++ b/src/pipecat/services/ollama/llm.py @@ -6,9 +6,21 @@ """OLLama LLM service implementation for Pipecat AI framework.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class OllamaLLMSettings(OpenAILLMSettings): + """Settings for Ollama LLM service.""" + + pass class OLLamaLLMService(OpenAILLMService): @@ -18,18 +30,43 @@ class OLLamaLLMService(OpenAILLMService): providing a compatible interface for running large language models locally. """ + _settings: OllamaLLMSettings + def __init__( - self, *, model: str = "llama2", base_url: str = "http://localhost:11434/v1", **kwargs + self, + *, + model: Optional[str] = None, + base_url: str = "http://localhost:11434/v1", + settings: Optional[OllamaLLMSettings] = None, + **kwargs, ): """Initialize OLLama LLM service. Args: model: The OLLama model to use. Defaults to "llama2". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for the OLLama API endpoint. Defaults to "http://localhost:11434/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(model=model, base_url=base_url, api_key="ollama", **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = OllamaLLMSettings(model="llama2") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OllamaLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(base_url=base_url, api_key="ollama", settings=default_settings, **kwargs) def create_client(self, base_url=None, **kwargs): """Create OpenAI-compatible client for Ollama. diff --git a/src/pipecat/services/openai/base_llm.py b/src/pipecat/services/openai/base_llm.py index dfef1ae90..5e59a5129 100644 --- a/src/pipecat/services/openai/base_llm.py +++ b/src/pipecat/services/openai/base_llm.py @@ -53,11 +53,9 @@ class OpenAILLMSettings(LLMSettings): Parameters: max_completion_tokens: Maximum completion tokens to generate. - service_tier: Service tier to use (e.g., "auto", "flex", "priority"). """ max_completion_tokens: int | _NotGiven = field(default_factory=lambda: _NOT_GIVEN) - service_tier: str | _NotGiven = field(default_factory=lambda: _NOT_GIVEN) class BaseOpenAILLMService(LLMService): @@ -75,6 +73,10 @@ class BaseOpenAILLMService(LLMService): class InputParams(BaseModel): """Input parameters for OpenAI model configuration. + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(...)`` instead of + ``params=InputParams(...)``. + Parameters: frequency_penalty: Penalty for frequent tokens (-2.0 to 2.0). presence_penalty: Penalty for new tokens (-2.0 to 2.0). @@ -108,56 +110,88 @@ class BaseOpenAILLMService(LLMService): def __init__( self, *, - model: str, + model: Optional[str] = None, api_key=None, base_url=None, organization=None, project=None, default_headers: Optional[Mapping[str, str]] = None, + service_tier: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[OpenAILLMSettings] = None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, - system_instruction: Optional[str] = None, **kwargs, ): """Initialize the BaseOpenAILLMService. Args: model: The OpenAI model name to use (e.g., "gpt-4.1", "gpt-4o"). + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_key: OpenAI API key. If None, uses environment variable. base_url: Custom base URL for OpenAI API. If None, uses default. organization: OpenAI organization ID. project: OpenAI project ID. default_headers: Additional HTTP headers to include in requests. + service_tier: Service tier to use (e.g., "auto", "flex", "priority"). params: Input parameters for model configuration and behavior. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. retry_timeout_secs: Request timeout in seconds. Defaults to 5.0 seconds. retry_on_timeout: Whether to retry the request once if it times out. - system_instruction: Optional system instruction to prepend to messages. **kwargs: Additional arguments passed to the parent LLMService. """ - params = params or BaseOpenAILLMService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings( + model="gpt-4o", + system_instruction=None, + frequency_penalty=NOT_GIVEN, + presence_penalty=NOT_GIVEN, + seed=NOT_GIVEN, + temperature=NOT_GIVEN, + top_p=NOT_GIVEN, + top_k=None, + max_tokens=NOT_GIVEN, + max_completion_tokens=NOT_GIVEN, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + extra={}, + ) + + # 2. Apply direct init arg overrides (no warnings in base class) + if model is not None: + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None and not settings: + default_settings.frequency_penalty = params.frequency_penalty + default_settings.presence_penalty = params.presence_penalty + default_settings.seed = params.seed + default_settings.temperature = params.temperature + default_settings.top_p = params.top_p + default_settings.max_tokens = params.max_tokens + default_settings.max_completion_tokens = params.max_completion_tokens + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=OpenAILLMSettings( - model=model, - frequency_penalty=params.frequency_penalty, - presence_penalty=params.presence_penalty, - seed=params.seed, - temperature=params.temperature, - top_p=params.top_p, - top_k=None, - max_tokens=params.max_tokens, - max_completion_tokens=params.max_completion_tokens, - service_tier=params.service_tier, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), + settings=default_settings, **kwargs, ) + self._service_tier = service_tier self._retry_timeout_secs = retry_timeout_secs self._retry_on_timeout = retry_on_timeout - self._system_instruction = system_instruction self._full_model_name: str = "" self._client = self.create_client( api_key=api_key, @@ -168,8 +202,8 @@ class BaseOpenAILLMService(LLMService): **kwargs, ) - if self._system_instruction: - logger.debug(f"{self}: Using system instruction: {self._system_instruction}") + if self._settings.system_instruction: + logger.debug(f"{self}: Using system instruction: {self._settings.system_instruction}") def create_client( self, @@ -284,7 +318,7 @@ class BaseOpenAILLMService(LLMService): "top_p": self._settings.top_p, "max_tokens": self._settings.max_tokens, "max_completion_tokens": self._settings.max_completion_tokens, - "service_tier": self._settings.service_tier, + "service_tier": self._service_tier if self._service_tier is not None else NOT_GIVEN, } # Messages, tools, tool_choice @@ -293,7 +327,7 @@ class BaseOpenAILLMService(LLMService): params.update(self._settings.extra) # Prepend system instruction from constructor, replacing any context system message - if self._system_instruction: + if self._settings.system_instruction: messages = params.get("messages", []) if messages and messages[0].get("role") == "system": logger.warning( @@ -301,7 +335,7 @@ class BaseOpenAILLMService(LLMService): " Using system_instruction." ) params["messages"] = [ - {"role": "system", "content": self._system_instruction} + {"role": "system", "content": self._settings.system_instruction} ] + messages return params diff --git a/src/pipecat/services/openai/image.py b/src/pipecat/services/openai/image.py index f35a5ded8..397d8c3d2 100644 --- a/src/pipecat/services/openai/image.py +++ b/src/pipecat/services/openai/image.py @@ -11,7 +11,7 @@ for creating images from text prompts. """ import io -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import AsyncGenerator, Literal, Optional import aiohttp @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( URLImageRawFrame, ) from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import NOT_GIVEN, ImageGenSettings, _NotGiven, _warn_deprecated_param @dataclass @@ -34,8 +34,11 @@ class OpenAIImageGenSettings(ImageGenSettings): Parameters: model: DALL-E model identifier. + image_size: Target size for generated images. """ + image_size: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + class OpenAIImageGenService(ImageGenService): """OpenAI DALL-E image generation service. @@ -45,14 +48,19 @@ class OpenAIImageGenService(ImageGenService): with configurable quality and style parameters. """ + _settings: OpenAIImageGenSettings + def __init__( self, *, api_key: str, base_url: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - image_size: Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"], - model: str = "dall-e-3", + image_size: Optional[ + Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"] + ] = None, + model: Optional[str] = None, + settings: Optional[OpenAIImageGenSettings] = None, ): """Initialize the OpenAI image generation service. @@ -60,11 +68,39 @@ class OpenAIImageGenService(ImageGenService): api_key: OpenAI API key for authentication. base_url: Custom base URL for OpenAI API. If None, uses default. aiohttp_session: HTTP session for downloading generated images. - image_size: Target size for generated images. + image_size: Target size for generated images. Defaults to "1024x1024". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAIImageGenSettings(image_size=...)`` instead. + model: DALL-E model to use for generation. Defaults to "dall-e-3". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAIImageGenSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. """ - super().__init__(settings=OpenAIImageGenSettings(model=model)) - self._image_size = image_size + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAIImageGenSettings( + model="dall-e-3", + image_size=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIImageGenSettings, "model") + default_settings.model = model + + if image_size is not None: + _warn_deprecated_param("image_size", OpenAIImageGenSettings, "image_size") + default_settings.image_size = image_size + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings) self._client = AsyncOpenAI(api_key=api_key, base_url=base_url) self._aiohttp_session = aiohttp_session @@ -80,7 +116,7 @@ class OpenAIImageGenService(ImageGenService): logger.debug(f"Generating image from prompt: {prompt}") image = await self._client.images.generate( - prompt=prompt, model=self._settings.model, n=1, size=self._image_size + prompt=prompt, model=self._settings.model, n=1, size=self._settings.image_size ) image_url = image.data[0].url diff --git a/src/pipecat/services/openai/llm.py b/src/pipecat/services/openai/llm.py index b760b0d6e..ab1384a4c 100644 --- a/src/pipecat/services/openai/llm.py +++ b/src/pipecat/services/openai/llm.py @@ -10,6 +10,8 @@ import json from dataclasses import dataclass from typing import Any, Optional +from openai import NOT_GIVEN + from pipecat.frames.frames import ( FunctionCallCancelFrame, FunctionCallInProgressFrame, @@ -23,7 +25,8 @@ from pipecat.processors.aggregators.llm_response import ( LLMUserContextAggregator, ) from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext -from pipecat.services.openai.base_llm import BaseOpenAILLMService +from pipecat.services.openai.base_llm import BaseOpenAILLMService, OpenAILLMSettings +from pipecat.services.settings import _warn_deprecated_param @dataclass @@ -72,18 +75,75 @@ class OpenAILLMService(BaseOpenAILLMService): def __init__( self, *, - model: str = "gpt-4.1", + model: Optional[str] = None, + service_tier: Optional[str] = None, params: Optional[BaseOpenAILLMService.InputParams] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize OpenAI LLM service. Args: model: The OpenAI model name to use. Defaults to "gpt-4.1". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + service_tier: Service tier to use (e.g., "auto", "flex", "priority"). params: Input parameters for model configuration. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent BaseOpenAILLMService. """ - super().__init__(model=model, params=params, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings( + model="gpt-4.1", + system_instruction=None, + frequency_penalty=NOT_GIVEN, + presence_penalty=NOT_GIVEN, + seed=NOT_GIVEN, + temperature=NOT_GIVEN, + top_p=NOT_GIVEN, + top_k=None, + max_tokens=NOT_GIVEN, + max_completion_tokens=NOT_GIVEN, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + extra={}, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # Handle service_tier from deprecated params + if params is not None and not settings and params.service_tier is not NOT_GIVEN: + service_tier = service_tier or params.service_tier + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", OpenAILLMSettings) + if not settings: + default_settings.frequency_penalty = params.frequency_penalty + default_settings.presence_penalty = params.presence_penalty + default_settings.seed = params.seed + default_settings.temperature = params.temperature + default_settings.top_p = params.top_p + default_settings.max_tokens = params.max_tokens + default_settings.max_completion_tokens = params.max_completion_tokens + if isinstance(params.extra, dict): + default_settings.extra = params.extra + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(service_tier=service_tier, settings=default_settings, **kwargs) def create_context_aggregator( self, diff --git a/src/pipecat/services/openai/realtime/llm.py b/src/pipecat/services/openai/realtime/llm.py index 07b6aa82b..b5d9dc8e2 100644 --- a/src/pipecat/services/openai/realtime/llm.py +++ b/src/pipecat/services/openai/realtime/llm.py @@ -10,7 +10,7 @@ import base64 import io import json import time -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Optional from loguru import logger @@ -59,7 +59,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import LLMSettings, _warn_deprecated_param from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt @@ -93,15 +93,9 @@ class CurrentAudioResponse: @dataclass class OpenAIRealtimeLLMSettings(LLMSettings): - """Settings for OpenAI Realtime LLM services. + """Settings for OpenAI Realtime LLM services.""" - Parameters: - session_properties: OpenAI Realtime session configuration. - """ - - session_properties: events.SessionProperties | _NotGiven = field( - default_factory=lambda: NOT_GIVEN - ) + pass class OpenAIRealtimeLLMService(LLMService): @@ -121,9 +115,10 @@ class OpenAIRealtimeLLMService(LLMService): self, *, api_key: str, - model: str = "gpt-realtime-1.5", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[OpenAIRealtimeLLMSettings] = None, start_audio_paused: bool = False, start_video_paused: bool = False, video_frame_detail: str = "auto", @@ -134,14 +129,18 @@ class OpenAIRealtimeLLMService(LLMService): Args: api_key: OpenAI API key for authentication. - model: OpenAI model name. Defaults to "gpt-realtime". + model: OpenAI model name. + + .. deprecated:: + Use ``settings=OpenAIRealtimeLLMSettings(model=...)`` instead. + This is a connection-level parameter set via the WebSocket URL query parameter and cannot be changed during the session. base_url: WebSocket base URL for the realtime API. Defaults to "wss://api.openai.com/v1/realtime". session_properties: Configuration properties for the realtime session. - These are session-level settings that can be updated during the session - (except for voice and model). If None, uses default SessionProperties. + If None, uses default SessionProperties. + settings: Runtime-updatable settings for this service. start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. video_frame_detail: Detail level for video processing. Can be "auto", "low", or "high". @@ -168,29 +167,42 @@ class OpenAIRealtimeLLMService(LLMService): stacklevel=2, ) + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAIRealtimeLLMSettings( + model="gpt-realtime-1.5", + system_instruction=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeLLMSettings, "model") + default_settings.model = model + + # 3. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + # Build WebSocket URL with model query parameter # Source: https://platform.openai.com/docs/guides/realtime-websocket - full_url = f"{base_url}?model={model}" + full_url = f"{base_url}?model={default_settings.model}" super().__init__( base_url=full_url, - settings=OpenAIRealtimeLLMSettings( - model=model, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) self.api_key = api_key self.base_url = full_url + self._session_properties = session_properties or events.SessionProperties() self._audio_input_paused = start_audio_paused self._video_input_paused = start_video_paused self._video_frame_detail = video_frame_detail @@ -253,12 +265,12 @@ class OpenAIRealtimeLLMService(LLMService): def _is_modality_enabled(self, modality: str) -> bool: """Check if a specific modality is enabled, "text" or "audio".""" - modalities = self._settings.session_properties.output_modalities or ["audio", "text"] + modalities = self._session_properties.output_modalities or ["audio", "text"] return modality in modalities def _get_enabled_modalities(self) -> list[str]: """Get the list of enabled modalities.""" - modalities = self._settings.session_properties.output_modalities or ["audio", "text"] + modalities = self._session_properties.output_modalities or ["audio", "text"] # API only supports single modality responses: either ["text"] or ["audio"] if "audio" in modalities: return ["audio"] @@ -331,9 +343,9 @@ class OpenAIRealtimeLLMService(LLMService): # None and False are different. Check for False. None means we're using OpenAI's # built-in turn detection defaults. turn_detection_disabled = ( - self._settings.session_properties.audio - and self._settings.session_properties.audio.input - and self._settings.session_properties.audio.input.turn_detection is False + self._session_properties.audio + and self._session_properties.audio.input + and self._session_properties.audio.input.turn_detection is False ) if turn_detection_disabled: await self.send_client_event(events.InputAudioBufferClearEvent()) @@ -353,9 +365,9 @@ class OpenAIRealtimeLLMService(LLMService): # None and False are different. Check for False. None means we're using OpenAI's # built-in turn detection defaults. turn_detection_disabled = ( - self._settings.session_properties.audio - and self._settings.session_properties.audio.input - and self._settings.session_properties.audio.input.turn_detection is False + self._session_properties.audio + and self._session_properties.audio.input + and self._session_properties.audio.input.turn_detection is False ) if turn_detection_disabled: await self.send_client_event(events.InputAudioBufferCommitEvent()) @@ -428,7 +440,7 @@ class OpenAIRealtimeLLMService(LLMService): # directly. The frame.delta path falls through to super, which calls # _update_settings → our override handles the rest. if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None: - self._settings.session_properties = events.SessionProperties(**frame.settings) + self._session_properties = events.SessionProperties(**frame.settings) await self._send_session_update() await self.push_frame(frame, direction) return @@ -547,15 +559,13 @@ class OpenAIRealtimeLLMService(LLMService): await self.push_error(error_msg=f"Error sending client event: {e}", exception=e) async def _update_settings(self, delta): - """Apply a settings delta, sending a session update if needed.""" + """Apply a settings delta.""" changed = await super()._update_settings(delta) - if "session_properties" in changed: - await self._send_session_update() - self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"}) + self._warn_unhandled_updated_settings(changed.keys()) return changed async def _send_session_update(self): - settings = self._settings.session_properties + settings = self._session_properties adapter: OpenAIRealtimeLLMAdapter = self.get_llm_adapter() if self._context: diff --git a/src/pipecat/services/openai/stt.py b/src/pipecat/services/openai/stt.py index 32895f8b5..0e1e4f594 100644 --- a/src/pipecat/services/openai/stt.py +++ b/src/pipecat/services/openai/stt.py @@ -35,10 +35,14 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import OPENAI_REALTIME_TTFS_P99, OPENAI_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_stt @@ -51,6 +55,13 @@ except ModuleNotFoundError: State = None +@dataclass +class OpenAISTTSettings(BaseWhisperSTTSettings): + """Settings for the OpenAI STT service.""" + + pass + + class OpenAISTTService(BaseWhisperSTTService): """OpenAI Speech-to-Text service that generates text from audio. @@ -58,44 +69,88 @@ class OpenAISTTService(BaseWhisperSTTService): set via the api_key parameter or OPENAI_API_KEY environment variable. """ + _settings: OpenAISTTSettings + def __init__( self, *, - model: str = "gpt-4o-transcribe", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, language: Optional[Language] = Language.EN, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[OpenAISTTSettings] = None, ttfs_p99_latency: Optional[float] = OPENAI_TTFS_P99, **kwargs, ): """Initialize OpenAI STT service. Args: - model: Model to use — either gpt-4o or Whisper. Defaults to "gpt-4o-transcribe". + model: Model to use — either gpt-4o or Whisper. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAISTTSettings(model=...)`` instead. + api_key: OpenAI API key. Defaults to None. base_url: API base URL. Defaults to None. language: Language of the audio input. Defaults to English. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAISTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAISTTSettings(prompt=...)`` instead. + temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAISTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ + # --- 1. Hardcoded defaults --- + _language = language or Language.EN + default_settings = OpenAISTTSettings( + model="gpt-4o-transcribe", + language=self.language_to_service_language(_language), + prompt=None, + temperature=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", OpenAISTTSettings, "model") + default_settings.model = model + if prompt is not None: + _warn_deprecated_param("prompt", OpenAISTTSettings, "prompt") + default_settings.prompt = prompt + if temperature is not None: + _warn_deprecated_param("temperature", OpenAISTTSettings, "temperature") + default_settings.temperature = temperature + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - model=model, api_key=api_key, base_url=base_url, - language=language, - prompt=prompt, - temperature=temperature, + settings=default_settings, ttfs_p99_latency=ttfs_p99_latency, **kwargs, ) async def _transcribe(self, audio: bytes) -> Transcription: - assert self._language is not None # Assigned in the BaseWhisperSTTService class + assert self._settings.language is not None # Build kwargs dict with only set parameters kwargs = { @@ -133,7 +188,7 @@ class OpenAIRealtimeSTTSettings(STTSettings): prompt: Optional prompt text to guide transcription style. """ - prompt: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class OpenAIRealtimeSTTService(WebsocketSTTService): @@ -175,13 +230,14 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): self, *, api_key: str, - model: str = "gpt-4o-transcribe", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", language: Optional[Language] = Language.EN, prompt: Optional[str] = None, turn_detection: Optional[Union[dict, Literal[False]]] = False, noise_reduction: Optional[Literal["near_field", "far_field"]] = None, should_interrupt: bool = True, + settings: Optional[OpenAIRealtimeSTTSettings] = None, ttfs_p99_latency: Optional[float] = OPENAI_REALTIME_TTFS_P99, **kwargs, ): @@ -191,12 +247,23 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): api_key: OpenAI API key for authentication. model: Transcription model. Supported values are ``"gpt-4o-transcribe"`` and ``"gpt-4o-mini-transcribe"``. - Defaults to ``"gpt-4o-transcribe"``. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAIRealtimeSTTSettings(model=...)`` instead. + base_url: WebSocket base URL for the Realtime API. Defaults to ``"wss://api.openai.com/v1/realtime"``. language: Language of the audio input. Defaults to English. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAIRealtimeSTTSettings(language=...)`` instead. + prompt: Optional prompt text to guide transcription style or provide keyword hints. + + .. deprecated:: 0.0.105 + Use ``settings=OpenAIRealtimeSTTSettings(prompt=...)`` instead. + turn_detection: Server-side VAD configuration. Defaults to ``False`` (disabled), which relies on a local VAD processor in the pipeline. Pass ``None`` to use server @@ -208,6 +275,8 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): should_interrupt: Whether to interrupt bot output when speech is detected by server-side VAD. Only applies when turn detection is enabled. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent @@ -219,20 +288,39 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): "Install it with: pip install pipecat-ai[openai]" ) + # --- 1. Hardcoded defaults --- + default_settings = OpenAIRealtimeSTTSettings( + model="gpt-4o-transcribe", + language=Language.EN, + prompt=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeSTTSettings, "model") + default_settings.model = model + if language is not None and language != Language.EN: + _warn_deprecated_param("language", OpenAIRealtimeSTTSettings, "language") + default_settings.language = language + if prompt is not None: + _warn_deprecated_param("prompt", OpenAIRealtimeSTTSettings, "prompt") + default_settings.prompt = prompt + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( ttfs_p99_latency=ttfs_p99_latency, - settings=OpenAIRealtimeSTTSettings( - model=model, - language=language, - prompt=prompt, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._base_url = base_url - self._prompt = prompt self._turn_detection = turn_detection self._noise_reduction = noise_reduction self._should_interrupt = should_interrupt @@ -269,8 +357,7 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): async def _update_settings(self, delta: STTSettings) -> dict[str, Any]: """Apply a settings delta and send session update if needed. - Keeps ``_language_code`` and ``_prompt`` in sync with settings - and sends a ``session.update`` to the server when the session is active. + Sends a ``session.update`` to the server when the session is active. Args: delta: A :class:`STTSettings` (or ``OpenAIRealtimeSTTSettings``) delta. @@ -280,13 +367,7 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): """ changed = await super()._update_settings(delta) - if not changed: - return changed - - if "prompt" in changed and isinstance(self._settings, OpenAIRealtimeSTTSettings): - self._prompt = self._settings.prompt - - if self._session_ready: + if changed and self._session_ready: await self._send_session_update() return changed @@ -443,8 +524,8 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): if language_code: transcription["language"] = language_code - if self._prompt: - transcription["prompt"] = self._prompt + if self._settings.prompt: + transcription["prompt"] = self._settings.prompt input_audio: dict = { "format": { diff --git a/src/pipecat/services/openai/tts.py b/src/pipecat/services/openai/tts.py index f95d79134..b4933ae9f 100644 --- a/src/pipecat/services/openai/tts.py +++ b/src/pipecat/services/openai/tts.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -90,6 +90,9 @@ class OpenAITTSService(TTSService): class InputParams(BaseModel): """Input parameters for OpenAI TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(...)`` instead. + Parameters: instructions: Instructions to guide voice synthesis behavior. speed: Voice speed control (0.25 to 4.0, default 1.0). @@ -103,12 +106,13 @@ class OpenAITTSService(TTSService): *, api_key: Optional[str] = None, base_url: Optional[str] = None, - voice: str = "alloy", - model: str = "gpt-4o-mini-tts", + voice: Optional[str] = None, + model: Optional[str] = None, sample_rate: Optional[int] = None, instructions: Optional[str] = None, speed: Optional[float] = None, params: Optional[InputParams] = None, + settings: Optional[OpenAITTSSettings] = None, **kwargs, ): """Initialize OpenAI TTS service. @@ -117,40 +121,80 @@ class OpenAITTSService(TTSService): api_key: OpenAI API key for authentication. If None, uses environment variable. base_url: Custom base URL for OpenAI API. If None, uses default. voice: Voice ID to use for synthesis. Defaults to "alloy". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(voice=...)`` instead. + model: TTS model to use. Defaults to "gpt-4o-mini-tts". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(model=...)`` instead. + sample_rate: Output audio sample rate in Hz. If None, uses OpenAI's default 24kHz. instructions: Optional instructions to guide voice synthesis behavior. - speed: Voice speed control (0.25 to 4.0, default 1.0). - params: Optional synthesis controls (acting instructions, speed, ...). - **kwargs: Additional keyword arguments passed to TTSService. - .. deprecated:: 0.0.91 - The `instructions` and `speed` parameters are deprecated, use `InputParams` instead. + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(instructions=...)`` instead. + + speed: Voice speed control (0.25 to 4.0, default 1.0). + + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(speed=...)`` instead. + + params: Optional synthesis controls (acting instructions, speed, ...). + + .. deprecated:: 0.0.105 + Use ``settings=OpenAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. + **kwargs: Additional keyword arguments passed to TTSService. """ if sample_rate and sample_rate != self.OPENAI_SAMPLE_RATE: logger.warning( f"OpenAI TTS only supports {self.OPENAI_SAMPLE_RATE}Hz sample rate. " f"Current rate of {sample_rate}Hz may cause issues." ) - if instructions or speed: - import warnings - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "The `instructions` and `speed` parameters are deprecated, use `InputParams` instead.", - DeprecationWarning, - stacklevel=2, - ) + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAITTSSettings( + model="gpt-4o-mini-tts", + voice="alloy", + language=None, + instructions=None, + speed=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice is not None: + _warn_deprecated_param("voice", OpenAITTSSettings, "voice") + default_settings.voice = voice + if model is not None: + _warn_deprecated_param("model", OpenAITTSSettings, "model") + default_settings.model = model + if instructions is not None: + _warn_deprecated_param("instructions", OpenAITTSSettings, "instructions") + default_settings.instructions = instructions + if speed is not None: + _warn_deprecated_param("speed", OpenAITTSSettings, "speed") + default_settings.speed = speed + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", OpenAITTSSettings) + if not settings: + if params.instructions is not None: + default_settings.instructions = params.instructions + if params.speed is not None: + default_settings.speed = params.speed + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=OpenAITTSSettings( - model=model, - voice=voice, - instructions=params.instructions if params else instructions, - speed=params.speed if params else speed, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/openai_realtime_beta/azure.py b/src/pipecat/services/openai_realtime_beta/azure.py index 6370ac0f4..72a1201f7 100644 --- a/src/pipecat/services/openai_realtime_beta/azure.py +++ b/src/pipecat/services/openai_realtime_beta/azure.py @@ -7,10 +7,11 @@ """Azure OpenAI Realtime Beta LLM service implementation.""" import warnings +from dataclasses import dataclass from loguru import logger -from .openai import OpenAIRealtimeBetaLLMService +from .openai import OpenAIRealtimeBetaLLMService, OpenAIRealtimeBetaLLMSettings try: from websockets.asyncio.client import connect as websocket_connect @@ -22,6 +23,13 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +@dataclass +class AzureRealtimeBetaLLMSettings(OpenAIRealtimeBetaLLMSettings): + """Settings for Azure Realtime Beta LLM service.""" + + pass + + class AzureRealtimeBetaLLMService(OpenAIRealtimeBetaLLMService): """Azure OpenAI Realtime Beta LLM service with Azure-specific authentication. @@ -34,6 +42,8 @@ class AzureRealtimeBetaLLMService(OpenAIRealtimeBetaLLMService): real-time audio and text communication capabilities as the base OpenAI service. """ + _settings: AzureRealtimeBetaLLMSettings + def __init__( self, *, diff --git a/src/pipecat/services/openai_realtime_beta/openai.py b/src/pipecat/services/openai_realtime_beta/openai.py index c912ed45c..a3f8e47fc 100644 --- a/src/pipecat/services/openai_realtime_beta/openai.py +++ b/src/pipecat/services/openai_realtime_beta/openai.py @@ -10,7 +10,7 @@ import base64 import json import time import warnings -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Optional from loguru import logger @@ -54,7 +54,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService from pipecat.services.openai.llm import OpenAIContextAggregatorPair -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import LLMSettings, _warn_deprecated_param from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt @@ -94,15 +94,9 @@ class CurrentAudioResponse: @dataclass class OpenAIRealtimeBetaLLMSettings(LLMSettings): - """Settings for OpenAI Realtime Beta LLM services. + """Settings for OpenAI Realtime Beta LLM services.""" - Parameters: - session_properties: OpenAI Realtime session configuration. - """ - - session_properties: events.SessionProperties | _NotGiven = field( - default_factory=lambda: NOT_GIVEN - ) + pass class OpenAIRealtimeBetaLLMService(LLMService): @@ -126,9 +120,10 @@ class OpenAIRealtimeBetaLLMService(LLMService): self, *, api_key: str, - model: str = "gpt-4o-realtime-preview-2025-06-03", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[OpenAIRealtimeBetaLLMSettings] = None, start_audio_paused: bool = False, send_transcription_frames: bool = True, **kwargs, @@ -137,11 +132,16 @@ class OpenAIRealtimeBetaLLMService(LLMService): Args: api_key: OpenAI API key for authentication. - model: OpenAI model name. Defaults to "gpt-4o-realtime-preview-2025-06-03". + model: OpenAI model name. + + .. deprecated:: + Use ``settings=OpenAIRealtimeBetaLLMSettings(model=...)`` instead. + base_url: WebSocket base URL for the realtime API. Defaults to "wss://api.openai.com/v1/realtime". session_properties: Configuration properties for the realtime session. If None, uses default SessionProperties. + settings: Runtime-updatable settings for this service. start_audio_paused: Whether to start with audio input paused. Defaults to False. send_transcription_frames: Whether to emit transcription frames. Defaults to True. **kwargs: Additional arguments passed to parent LLMService. @@ -155,27 +155,39 @@ class OpenAIRealtimeBetaLLMService(LLMService): stacklevel=2, ) - full_url = f"{base_url}?model={model}" + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAIRealtimeBetaLLMSettings( + model="gpt-4o-realtime-preview-2025-06-03", + system_instruction=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeBetaLLMSettings, "model") + default_settings.model = model + # 3. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + full_url = f"{base_url}?model={default_settings.model}" super().__init__( base_url=full_url, - settings=OpenAIRealtimeBetaLLMSettings( - model=model, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) self.api_key = api_key self.base_url = full_url + self._session_properties = session_properties or events.SessionProperties() self._audio_input_paused = start_audio_paused self._send_transcription_frames = send_transcription_frames self._websocket = None @@ -214,12 +226,12 @@ class OpenAIRealtimeBetaLLMService(LLMService): def _is_modality_enabled(self, modality: str) -> bool: """Check if a specific modality is enabled, "text" or "audio".""" - modalities = self._settings.session_properties.modalities or ["audio", "text"] + modalities = self._session_properties.modalities or ["audio", "text"] return modality in modalities def _get_enabled_modalities(self) -> list[str]: """Get the list of enabled modalities.""" - return self._settings.session_properties.modalities or ["audio", "text"] + return self._session_properties.modalities or ["audio", "text"] async def retrieve_conversation_item(self, item_id: str): """Retrieve a conversation item by ID from the server. @@ -286,7 +298,7 @@ class OpenAIRealtimeBetaLLMService(LLMService): async def _handle_interruption(self): # None and False are different. Check for False. None means we're using OpenAI's # built-in turn detection defaults. - if self._settings.session_properties.turn_detection is False: + if self._session_properties.turn_detection is False: await self.send_client_event(events.InputAudioBufferClearEvent()) await self.send_client_event(events.ResponseCancelEvent()) await self._truncate_current_audio_response() @@ -303,7 +315,7 @@ class OpenAIRealtimeBetaLLMService(LLMService): async def _handle_user_stopped_speaking(self, frame): # None and False are different. Check for False. None means we're using OpenAI's # built-in turn detection defaults. - if self._settings.session_properties.turn_detection is False: + if self._session_properties.turn_detection is False: await self.send_client_event(events.InputAudioBufferCommitEvent()) await self.send_client_event(events.ResponseCreateEvent()) @@ -374,7 +386,7 @@ class OpenAIRealtimeBetaLLMService(LLMService): # directly. The frame.delta path falls through to super, which calls # _update_settings → our override handles the rest. if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None: - self._settings.session_properties = events.SessionProperties(**frame.settings) + self._session_properties = events.SessionProperties(**frame.settings) await self._send_session_update() await self.push_frame(frame, direction) return @@ -491,14 +503,13 @@ class OpenAIRealtimeBetaLLMService(LLMService): await self.push_error(error_msg=f"Error sending client event: {e}", exception=e) async def _update_settings(self, delta): - """Apply a settings delta, sending a session update if needed.""" + """Apply a settings delta.""" changed = await super()._update_settings(delta) - if "session_properties" in changed: - await self._send_session_update() + self._warn_unhandled_updated_settings(changed.keys()) return changed async def _send_session_update(self): - settings = self._settings.session_properties + settings = self._session_properties # tools given in the context override the tools in the session properties if self._context and self._context.tools: settings.tools = self._context.tools diff --git a/src/pipecat/services/openpipe/llm.py b/src/pipecat/services/openpipe/llm.py index fa53c1554..f6437feef 100644 --- a/src/pipecat/services/openpipe/llm.py +++ b/src/pipecat/services/openpipe/llm.py @@ -10,12 +10,15 @@ This module provides an OpenPipe-specific implementation of the OpenAI LLM servi enabling integration with OpenPipe's fine-tuning and monitoring capabilities. """ +from dataclasses import dataclass from typing import Dict, Optional from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param try: from openpipe import AsyncOpenAI as OpenPipeAI @@ -25,6 +28,13 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +@dataclass +class OpenPipeLLMSettings(OpenAILLMSettings): + """Settings for OpenPipe LLM service.""" + + pass + + class OpenPipeLLMService(OpenAILLMService): """OpenPipe-powered Large Language Model service. @@ -33,34 +43,55 @@ class OpenPipeLLMService(OpenAILLMService): for model training and evaluation. """ + _settings: OpenPipeLLMSettings + def __init__( self, *, - model: str = "gpt-4.1", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, openpipe_api_key: Optional[str] = None, openpipe_base_url: str = "https://app.openpipe.ai/api/v1", tags: Optional[Dict[str, str]] = None, + settings: Optional[OpenPipeLLMSettings] = None, **kwargs, ): """Initialize OpenPipe LLM service. Args: model: The model name to use. Defaults to "gpt-4.1". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_key: OpenAI API key for authentication. If None, reads from environment. base_url: Custom OpenAI API endpoint URL. Uses default if None. openpipe_api_key: OpenPipe API key for enhanced features. If None, reads from environment. openpipe_base_url: OpenPipe API endpoint URL. Defaults to "https://app.openpipe.ai/api/v1". tags: Optional dictionary of tags to apply to all requests for tracking. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent OpenAILLMService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenPipeLLMSettings(model="gpt-4.1") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenPipeLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - model=model, api_key=api_key, base_url=base_url, openpipe_api_key=openpipe_api_key, openpipe_base_url=openpipe_base_url, + settings=default_settings, **kwargs, ) self._tags = tags diff --git a/src/pipecat/services/openrouter/llm.py b/src/pipecat/services/openrouter/llm.py index c33fda2fc..03591de46 100644 --- a/src/pipecat/services/openrouter/llm.py +++ b/src/pipecat/services/openrouter/llm.py @@ -10,11 +10,21 @@ This module provides an OpenAI-compatible interface for interacting with OpenRou extending the base OpenAI LLM service functionality. """ +from dataclasses import dataclass from typing import Any, Dict, Optional from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class OpenRouterLLMSettings(OpenAILLMSettings): + """Settings for OpenRouter LLM service.""" + + pass class OpenRouterLLMService(OpenAILLMService): @@ -24,12 +34,15 @@ class OpenRouterLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: OpenRouterLLMSettings + def __init__( self, *, api_key: Optional[str] = None, - model: str = "openai/gpt-4o-2024-11-20", + model: Optional[str] = None, base_url: str = "https://openrouter.ai/api/v1", + settings: Optional[OpenRouterLLMSettings] = None, **kwargs, ): """Initialize the OpenRouter LLM service. @@ -38,13 +51,31 @@ class OpenRouterLLMService(OpenAILLMService): api_key: The API key for accessing OpenRouter's API. If None, will attempt to read from environment variables. model: The model identifier to use. Defaults to "openai/gpt-4o-2024-11-20". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for OpenRouter API. Defaults to "https://openrouter.ai/api/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenRouterLLMSettings(model="openai/gpt-4o-2024-11-20") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenRouterLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( api_key=api_key, base_url=base_url, - model=model, + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/perplexity/llm.py b/src/pipecat/services/perplexity/llm.py index e03bace8d..137fdeeb9 100644 --- a/src/pipecat/services/perplexity/llm.py +++ b/src/pipecat/services/perplexity/llm.py @@ -11,11 +11,23 @@ an OpenAI-compatible interface. It handles Perplexity's unique token usage reporting patterns while maintaining compatibility with the Pipecat framework. """ +from dataclasses import dataclass +from typing import Optional + from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class PerplexityLLMSettings(OpenAILLMSettings): + """Settings for Perplexity LLM service.""" + + pass class PerplexityLLMService(OpenAILLMService): @@ -26,12 +38,15 @@ class PerplexityLLMService(OpenAILLMService): in token usage reporting between Perplexity (incremental) and OpenAI (final summary). """ + _settings: PerplexityLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.perplexity.ai", - model: str = "sonar", + model: Optional[str] = None, + settings: Optional[PerplexityLLMSettings] = None, **kwargs, ): """Initialize the Perplexity LLM service. @@ -40,9 +55,27 @@ class PerplexityLLMService(OpenAILLMService): api_key: The API key for accessing Perplexity's API. base_url: The base URL for Perplexity's API. Defaults to "https://api.perplexity.ai". model: The model identifier to use. Defaults to "sonar". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = PerplexityLLMSettings(model="sonar") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", PerplexityLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Counters for accumulating token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 @@ -81,6 +114,13 @@ class PerplexityLLMService(OpenAILLMService): if self._settings.max_tokens is not None: params["max_tokens"] = self._settings.max_tokens + # Prepend system instruction if set + if self._settings.system_instruction: + messages = params.get("messages", []) + params["messages"] = [ + {"role": "system", "content": self._settings.system_instruction} + ] + messages + return params async def _process_context(self, context: OpenAILLMContext | LLMContext): diff --git a/src/pipecat/services/piper/tts.py b/src/pipecat/services/piper/tts.py index c4831b839..46bf98cd1 100644 --- a/src/pipecat/services/piper/tts.py +++ b/src/pipecat/services/piper/tts.py @@ -20,7 +20,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import TTSSettings +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -53,41 +53,63 @@ class PiperTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, download_dir: Optional[Path] = None, force_redownload: bool = False, use_cuda: bool = False, + settings: Optional[PiperTTSSettings] = None, **kwargs, ): """Initialize the Piper TTS service. Args: voice_id: Piper voice model identifier (e.g. `en_US-ryan-high`). + + .. deprecated:: 0.0.105 + Use ``settings=PiperTTSSettings(voice=...)`` instead. + download_dir: Directory for storing voice model files. Defaults to the current working directory. force_redownload: Re-download the voice model even if it already exists. use_cuda: Use CUDA for GPU-accelerated inference. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent `TTSService`. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = PiperTTSSettings(model=None, voice=None, language=None) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", PiperTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. No params for this service + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=PiperTTSSettings(model=None, voice=voice_id, language=None), + settings=default_settings, **kwargs, ) download_dir = download_dir or Path.cwd() - model_file = f"{voice_id}.onnx" - model_path = Path(download_dir) / model_file + _voice = self._settings.voice + model_file = f"{_voice}.onnx" + model_path_resolved = Path(download_dir) / model_file - if not model_path.exists(): - logger.debug(f"Downloading Piper '{voice_id}' model") - download_voice(voice_id, download_dir, force_redownload=force_redownload) + if not model_path_resolved.exists(): + logger.debug(f"Downloading Piper '{_voice}' model") + download_voice(_voice, download_dir, force_redownload=force_redownload) - logger.debug(f"Loading Piper '{voice_id}' model from {model_path}") + logger.debug(f"Loading Piper '{_voice}' model from {model_path_resolved}") - self._voice = PiperVoice.load(model_path, use_cuda=use_cuda) + self._voice = PiperVoice.load(model_path_resolved, use_cuda=use_cuda) - logger.debug(f"Loaded Piper '{voice_id}' model") + logger.debug(f"Loaded Piper '{_voice}' model") def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -190,6 +212,7 @@ class PiperHttpTTSService(TTSService): base_url: str, aiohttp_session: aiohttp.ClientSession, voice_id: Optional[str] = None, + settings: Optional[PiperHttpTTSSettings] = None, **kwargs, ): """Initialize the Piper TTS service. @@ -198,10 +221,30 @@ class PiperHttpTTSService(TTSService): base_url: Base URL for the Piper TTS HTTP server. aiohttp_session: aiohttp ClientSession for making HTTP requests. voice_id: Piper voice model identifier (e.g. `en_US-ryan-high`). + + .. deprecated:: 0.0.105 + Use ``settings=PiperHttpTTSSettings(voice=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = PiperHttpTTSSettings(model=None, voice=None, language=None) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", PiperHttpTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. No params for this service + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=PiperHttpTTSSettings(model=None, voice=voice_id, language=None), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/qwen/llm.py b/src/pipecat/services/qwen/llm.py index 6b58faea2..e08566418 100644 --- a/src/pipecat/services/qwen/llm.py +++ b/src/pipecat/services/qwen/llm.py @@ -6,9 +6,21 @@ """Qwen LLM service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class QwenLLMSettings(OpenAILLMSettings): + """Settings for Qwen LLM service.""" + + pass class QwenLLMService(OpenAILLMService): @@ -18,12 +30,15 @@ class QwenLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: QwenLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", - model: str = "qwen-plus", + model: Optional[str] = None, + settings: Optional[QwenLLMSettings] = None, **kwargs, ): """Initialize the Qwen LLM service. @@ -32,10 +47,28 @@ class QwenLLMService(OpenAILLMService): api_key: The API key for accessing Qwen's API (DashScope API key). base_url: Base URL for Qwen API. Defaults to "https://dashscope-intl.aliyuncs.com/compatible-mode/v1". model: The model identifier to use. Defaults to "qwen-plus". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) - logger.info(f"Initialized Qwen LLM service with model: {model}") + # 1. Initialize default_settings with hardcoded defaults + default_settings = QwenLLMSettings(model="qwen-plus") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", QwenLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) + logger.info(f"Initialized Qwen LLM service with model: {self._settings.model}") def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Qwen API endpoint. diff --git a/src/pipecat/services/resembleai/tts.py b/src/pipecat/services/resembleai/tts.py index 1c2953b72..e1c1cf68a 100644 --- a/src/pipecat/services/resembleai/tts.py +++ b/src/pipecat/services/resembleai/tts.py @@ -8,8 +8,8 @@ import base64 import json -from dataclasses import dataclass, field -from typing import AsyncGenerator, ClassVar, Dict, Optional +from dataclasses import dataclass +from typing import AsyncGenerator, Optional from loguru import logger @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -38,22 +38,9 @@ except ModuleNotFoundError as e: @dataclass class ResembleAITTSSettings(TTSSettings): - """Settings for Resemble AI TTS service. + """Settings for Resemble AI TTS service.""" - Parameters: - precision: PCM bit depth (PCM_32, PCM_24, PCM_16, or MULAW). - output_format: Audio format (wav or mp3). - resemble_sample_rate: Audio sample rate sent to the API. - """ - - precision: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_format: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - resemble_sample_rate: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - - _aliases: ClassVar[Dict[str, str]] = { - "voice_id": "voice", - "sample_rate": "resemble_sample_rate", - } + pass class ResembleAITTSService(AudioContextTTSService): @@ -70,11 +57,12 @@ class ResembleAITTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://websocket.cluster.resemble.ai/stream", precision: Optional[str] = "PCM_16", output_format: Optional[str] = "wav", sample_rate: Optional[int] = 22050, + settings: Optional[ResembleAITTSSettings] = None, **kwargs, ): """Initialize the Resemble AI TTS service. @@ -82,30 +70,52 @@ class ResembleAITTSService(AudioContextTTSService): Args: api_key: Resemble AI API key for authentication. voice_id: Voice UUID to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=ResembleAITTSSettings(voice=...)`` instead. + url: WebSocket URL for Resemble AI TTS API. precision: PCM bit depth (PCM_32, PCM_24, PCM_16, or MULAW). output_format: Audio format (wav or mp3). sample_rate: Audio sample rate (8000, 16000, 22050, 32000, or 44100). Defaults to 22050. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = ResembleAITTSSettings( + model=None, + voice=None, + language=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", ResembleAITTSSettings, "voice") + default_settings.voice = voice_id + + # 3. No params for this service + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, reuse_context_id_within_turn=False, supports_word_timestamps=True, - settings=ResembleAITTSSettings( - model=None, - voice=voice_id, - language=None, - precision=precision, - output_format=output_format, - resemble_sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key self._url = url + # Init-only audio format config (not runtime-updatable). + self._precision = precision or "PCM_16" + self._output_format = output_format or "wav" + self._resemble_sample_rate = 0 # Set in start() + self._websocket = None self._request_id_counter = 0 self._receive_task = None @@ -147,9 +157,9 @@ class ResembleAITTSService(AudioContextTTSService): "data": text, "binary_response": False, # Use JSON frames to get timestamps "request_id": self._request_id_counter, # ResembleAI only accepts number - "output_format": self._settings.output_format, - "sample_rate": self._settings.resemble_sample_rate, - "precision": self._settings.precision, + "output_format": self._output_format, + "sample_rate": self._resemble_sample_rate, + "precision": self._precision, "no_audio_header": True, } @@ -163,7 +173,7 @@ class ResembleAITTSService(AudioContextTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.resemble_sample_rate = self.sample_rate + self._resemble_sample_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): diff --git a/src/pipecat/services/rime/tts.py b/src/pipecat/services/rime/tts.py index 944ff4e58..04ebcd5fc 100644 --- a/src/pipecat/services/rime/tts.py +++ b/src/pipecat/services/rime/tts.py @@ -31,7 +31,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import ( AudioContextTTSService, InterruptibleTTSService, @@ -76,8 +76,6 @@ class RimeTTSSettings(TTSSettings): """Settings for Rime WS JSON and HTTP TTS services. Parameters: - audioFormat: Audio output format. - samplingRate: Audio sample rate. segment: Text segmentation mode ("immediate", "bySentence", "never"). speedAlpha: Speech speed multiplier (mistv2 only). reduceLatency: Whether to reduce latency at potential quality cost (mistv2 only). @@ -91,8 +89,6 @@ class RimeTTSSettings(TTSSettings): top_p: Cumulative probability threshold (arcana only, 0.0-1.0). """ - audioFormat: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - samplingRate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) segment: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) speedAlpha: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) reduceLatency: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -113,16 +109,12 @@ class RimeNonJsonTTSSettings(TTSSettings): """Settings for Rime non-JSON WS TTS service. Parameters: - audioFormat: Audio output format. - samplingRate: Audio sample rate. segment: Text segmentation mode ("immediate", "bySentence", "never"). repetition_penalty: Token repetition penalty (1.0-2.0). temperature: Sampling temperature (0.0-1.0). top_p: Cumulative probability threshold (0.0-1.0). """ - audioFormat: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - samplingRate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) segment: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) repetition_penalty: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) temperature: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -144,6 +136,9 @@ class RimeTTSService(AudioContextTTSService): class InputParams(BaseModel): """Configuration parameters for Rime TTS service. + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. segment: Text segmentation mode ("immediate", "bySentence", "never"). @@ -176,11 +171,12 @@ class RimeTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://users-ws.rime.ai/ws3", - model: str = "arcana", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeTTSSettings] = None, text_aggregator: Optional[BaseTextAggregator] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, @@ -191,10 +187,24 @@ class RimeTTSService(AudioContextTTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(voice=...)`` instead. + url: Rime websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregator: Custom text aggregator for processing input text. .. deprecated:: 0.0.95 @@ -208,8 +218,57 @@ class RimeTTSService(AudioContextTTSService): **kwargs: Additional arguments passed to parent class. """ - # Initialize with parent class settings for proper frame handling - params = params or RimeTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = RimeTTSSettings( + model="arcana", + voice=None, + language=None, + segment=None, + inlineSpeedAlpha=None, + speedAlpha=None, + # Arcana params + repetition_penalty=None, + temperature=None, + top_p=None, + # Mistv2 params + reduceLatency=None, + pauseBetweenBrackets=None, + phonemizeBetweenBrackets=None, + noTextNormalization=None, + saveOovs=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", RimeTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", RimeTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", RimeTTSSettings) + if not settings: + default_settings.language = ( + self.language_to_service_language(params.language) if params.language else None + ) + default_settings.segment = params.segment + default_settings.speedAlpha = params.speed_alpha + # Arcana params + default_settings.repetition_penalty = params.repetition_penalty + default_settings.temperature = params.temperature + default_settings.top_p = params.top_p + # Mistv2 params + default_settings.reduceLatency = params.reduce_latency + default_settings.pauseBetweenBrackets = params.pause_between_brackets + default_settings.phonemizeBetweenBrackets = params.phonemize_between_brackets + default_settings.noTextNormalization = params.no_text_normalization + default_settings.saveOovs = params.save_oovs + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -220,31 +279,14 @@ class RimeTTSService(AudioContextTTSService): supports_word_timestamps=True, append_trailing_space=True, sample_rate=sample_rate, - settings=RimeTTSSettings( - model=model, - voice=voice_id, - audioFormat="pcm", - samplingRate=0, # updated in start() - language=self.language_to_service_language(params.language) - if params.language - else None, - segment=params.segment, - inlineSpeedAlpha=None, # Not applicable here - speedAlpha=params.speed_alpha, - # Arcana params - repetition_penalty=params.repetition_penalty, - temperature=params.temperature, - top_p=params.top_p, - # Mistv2 params - reduceLatency=params.reduce_latency, - pauseBetweenBrackets=params.pause_between_brackets, - phonemizeBetweenBrackets=params.phonemize_between_brackets, - noTextNormalization=params.no_text_normalization, - saveOovs=params.save_oovs, - ), + settings=default_settings, **kwargs, ) + # Init-only audio format fields (not runtime-updatable) + self._audio_format = "pcm" + self._sampling_rate = 0 # updated in start() + if not text_aggregator: # Always skip tags added for spelled-out text # Note: This is primarily to support backwards compatibility. @@ -294,8 +336,8 @@ class RimeTTSService(AudioContextTTSService): params: dict[str, Any] = { "speaker": self._settings.voice, "modelId": self._settings.model, - "audioFormat": self._settings.audioFormat, - "samplingRate": self._settings.samplingRate, + "audioFormat": self._audio_format, + "samplingRate": self._sampling_rate, } if self._settings.language is not None: params["lang"] = self._settings.language @@ -389,7 +431,7 @@ class RimeTTSService(AudioContextTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.samplingRate = self.sample_rate + self._sampling_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -628,6 +670,9 @@ class RimeHttpTTSService(TTSService): class InputParams(BaseModel): """Configuration parameters for Rime HTTP TTS service. + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. pause_between_brackets: Whether to add pauses between bracketed content. @@ -648,11 +693,12 @@ class RimeHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "mistv2", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeTTSSettings] = None, **kwargs, ): """Initialize Rime HTTP TTS service. @@ -660,36 +706,74 @@ class RimeHttpTTSService(TTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. model: Model ID to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=RimeTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or RimeHttpTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = RimeTTSSettings( + model="mistv2", + voice=None, + language="eng", + segment=None, + speedAlpha=None, + reduceLatency=None, + pauseBetweenBrackets=None, + phonemizeBetweenBrackets=None, + noTextNormalization=None, + saveOovs=None, + inlineSpeedAlpha=None, + repetition_penalty=None, + temperature=None, + top_p=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", RimeTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", RimeTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", RimeTTSSettings) + if not settings: + default_settings.language = ( + self.language_to_service_language(params.language) if params.language else "eng" + ) + default_settings.speedAlpha = params.speed_alpha + default_settings.reduceLatency = params.reduce_latency + default_settings.pauseBetweenBrackets = params.pause_between_brackets + default_settings.phonemizeBetweenBrackets = params.phonemize_between_brackets + default_settings.inlineSpeedAlpha = ( + params.inline_speed_alpha if params.inline_speed_alpha else None + ) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=RimeTTSSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "eng", - audioFormat="pcm", - samplingRate=0, - segment=None, - speedAlpha=params.speed_alpha, - reduceLatency=params.reduce_latency, - pauseBetweenBrackets=params.pause_between_brackets, - phonemizeBetweenBrackets=params.phonemize_between_brackets, - noTextNormalization=None, - saveOovs=None, - inlineSpeedAlpha=params.inline_speed_alpha if params.inline_speed_alpha else None, - repetition_penalty=None, - temperature=None, - top_p=None, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -697,6 +781,9 @@ class RimeHttpTTSService(TTSService): self._session = aiohttp_session self._base_url = "https://users.rime.ai/v1/rime-tts" + # Init-only audio format fields (not runtime-updatable) + self._audio_format = "pcm" + def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -810,6 +897,9 @@ class RimeNonJsonTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Configuration parameters for Rime Non-JSON WebSocket TTS service. + .. deprecated:: 0.0.105 + Use ``settings=RimeNonJsonTTSSettings(...)`` instead. + Args: language: Language for synthesis. Defaults to English. segment: Text segmentation mode ("immediate", "bySentence", "never"). @@ -830,12 +920,13 @@ class RimeNonJsonTTSService(InterruptibleTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://users.rime.ai/ws", - model: str = "arcana", + model: Optional[str] = None, audio_format: str = "pcm", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeNonJsonTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -845,11 +936,25 @@ class RimeNonJsonTTSService(InterruptibleTTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 0.0.105 + Use ``settings=RimeNonJsonTTSSettings(voice=...)`` instead. + url: Rime websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=RimeNonJsonTTSSettings(model=...)`` instead. + audio_format: Audio format to use. sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 0.0.105 + Use ``settings=RimeNonJsonTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -860,7 +965,41 @@ class RimeNonJsonTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent class. """ - params = params or RimeNonJsonTTSService.InputParams() + # 1. Initialize default_settings with hardcoded defaults + default_settings = RimeNonJsonTTSSettings( + voice=None, + model="arcana", + language=None, + segment=None, + repetition_penalty=None, + temperature=None, + top_p=None, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", RimeNonJsonTTSSettings, "voice") + default_settings.voice = voice_id + if model is not None: + _warn_deprecated_param("model", RimeNonJsonTTSSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", RimeNonJsonTTSSettings) + if not settings: + default_settings.language = ( + self.language_to_service_language(params.language) if params.language else None + ) + default_settings.segment = params.segment + default_settings.repetition_penalty = params.repetition_penalty + default_settings.temperature = params.temperature + default_settings.top_p = params.top_p + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, aggregate_sentences=aggregate_sentences, @@ -868,25 +1007,18 @@ class RimeNonJsonTTSService(InterruptibleTTSService): push_stop_frames=True, pause_frame_processing=True, append_trailing_space=True, - settings=RimeNonJsonTTSSettings( - voice=voice_id, - model=model, - audioFormat=audio_format, - samplingRate=sample_rate, - language=self.language_to_service_language(params.language) - if params.language - else None, - segment=params.segment, - repetition_penalty=params.repetition_penalty, - temperature=params.temperature, - top_p=params.top_p, - ), + settings=default_settings, **kwargs, ) + + # Init-only audio format fields (not runtime-updatable) + self._audio_format = audio_format + self._sampling_rate = sample_rate + self._api_key = api_key self._url = url # Add any extra parameters for future compatibility - if params.extra: + if params and params.extra: self._settings.extra.update(params.extra) self._receive_task = None @@ -919,7 +1051,7 @@ class RimeNonJsonTTSService(InterruptibleTTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.samplingRate = self.sample_rate + self._sampling_rate = self.sample_rate await self._connect() async def stop(self, frame: EndFrame): @@ -967,8 +1099,8 @@ class RimeNonJsonTTSService(InterruptibleTTSService): settings_dict = { "speaker": self._settings.voice, "modelId": self._settings.model, - "audioFormat": self._settings.audioFormat, - "samplingRate": self._settings.samplingRate, + "audioFormat": self._audio_format, + "samplingRate": self._sampling_rate, } if self._settings.language is not None: settings_dict["lang"] = self._settings.language diff --git a/src/pipecat/services/sambanova/llm.py b/src/pipecat/services/sambanova/llm.py index 016e1740d..0c92db098 100644 --- a/src/pipecat/services/sambanova/llm.py +++ b/src/pipecat/services/sambanova/llm.py @@ -7,6 +7,7 @@ """SambaNova LLM service implementation using OpenAI-compatible interface.""" import json +from dataclasses import dataclass from typing import Any, Dict, Optional from loguru import logger @@ -21,10 +22,19 @@ from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.services.llm_service import FunctionCallFromLLM +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param from pipecat.utils.tracing.service_decorators import traced_llm +@dataclass +class SambaNovaLLMSettings(OpenAILLMSettings): + """Settings for SambaNova LLM service.""" + + pass + + class SambaNovaLLMService(OpenAILLMService): # type: ignore """A service for interacting with SambaNova using the OpenAI-compatible interface. @@ -32,12 +42,15 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: SambaNovaLLMSettings + def __init__( self, *, api_key: str, - model: str = "Llama-4-Maverick-17B-128E-Instruct", + model: Optional[str] = None, base_url: str = "https://api.sambanova.ai/v1", + settings: Optional[SambaNovaLLMSettings] = None, **kwargs: Dict[Any, Any], ) -> None: """Initialize SambaNova LLM service. @@ -45,10 +58,28 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore Args: api_key: The API key for accessing SambaNova API. model: The model identifier to use. Defaults to "Llama-4-Maverick-17B-128E-Instruct". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for SambaNova API. Defaults to "https://api.sambanova.ai/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = SambaNovaLLMSettings(model="Llama-4-Maverick-17B-128E-Instruct") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", SambaNovaLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client( self, @@ -97,6 +128,14 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore params.update(params_from_context) params.update(self._settings.extra) + + # Prepend system instruction if set + if self._settings.system_instruction: + messages = params.get("messages", []) + params["messages"] = [ + {"role": "system", "content": self._settings.system_instruction} + ] + messages + return params @traced_llm # type: ignore diff --git a/src/pipecat/services/sambanova/stt.py b/src/pipecat/services/sambanova/stt.py index f313f0d7b..822c44da9 100644 --- a/src/pipecat/services/sambanova/stt.py +++ b/src/pipecat/services/sambanova/stt.py @@ -6,15 +6,28 @@ """SambaNova's Speech-to-Text service implementation for real-time transcription.""" +from dataclasses import dataclass from typing import Any, Optional from loguru import logger +from pipecat.services.settings import _warn_deprecated_param from pipecat.services.stt_latency import SAMBANOVA_TTFS_P99 -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language +@dataclass +class SambaNovaSTTSettings(BaseWhisperSTTSettings): + """Settings for the SambaNova STT service.""" + + pass + + class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore """SambaNova Whisper speech-to-text service. @@ -25,41 +38,85 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore def __init__( self, *, - model: str = "Whisper-Large-v3", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: str = "https://api.sambanova.ai/v1", - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[SambaNovaSTTSettings] = None, ttfs_p99_latency: Optional[float] = SAMBANOVA_TTFS_P99, **kwargs: Any, ) -> None: """Initialize SambaNova STT service. Args: - model: Whisper model to use. Defaults to "Whisper-Large-v3". + model: Whisper model to use. + + .. deprecated:: 0.0.105 + Use ``settings=SambaNovaSTTSettings(model=...)`` instead. + api_key: SambaNova API key. Defaults to None. base_url: API base URL. Defaults to "https://api.sambanova.ai/v1". - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 0.0.105 + Use ``settings=SambaNovaSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 0.0.105 + Use ``settings=SambaNovaSTTSettings(prompt=...)`` instead. + + temperature: Optional sampling temperature between 0 and 1. + + .. deprecated:: 0.0.105 + Use ``settings=SambaNovaSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to `pipecat.services.whisper.base_stt.BaseWhisperSTTService`. """ + # --- 1. Hardcoded defaults --- + default_settings = SambaNovaSTTSettings( + model="Whisper-Large-v3", + language=self.language_to_service_language(Language.EN), + prompt=None, + temperature=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", SambaNovaSTTSettings, "model") + default_settings.model = model + if language is not None: + _warn_deprecated_param("language", SambaNovaSTTSettings, "language") + default_settings.language = self.language_to_service_language(language) + if prompt is not None: + _warn_deprecated_param("prompt", SambaNovaSTTSettings, "prompt") + default_settings.prompt = prompt + if temperature is not None: + _warn_deprecated_param("temperature", SambaNovaSTTSettings, "temperature") + default_settings.temperature = temperature + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - model=model, api_key=api_key, base_url=base_url, - language=language, - prompt=prompt, - temperature=temperature, + settings=default_settings, ttfs_p99_latency=ttfs_p99_latency, **kwargs, ) async def _transcribe(self, audio: bytes) -> Transcription: - assert self._language is not None # Assigned in the BaseWhisperSTTService class + assert self._settings.language is not None if self._include_prob_metrics: # https://docs.sambanova.ai/docs/en/features/audio#request-parameters @@ -74,13 +131,13 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore "file": ("audio.wav", audio, "audio/wav"), "model": self._settings.model, "response_format": "json", - "language": self._language, + "language": self._settings.language, } - if self._prompt is not None: - kwargs["prompt"] = self._prompt + if self._settings.prompt is not None: + kwargs["prompt"] = self._settings.prompt - if self._temperature is not None: - kwargs["temperature"] = self._temperature + if self._settings.temperature is not None: + kwargs["temperature"] = self._settings.temperature return await self._client.audio.transcriptions.create(**kwargs) diff --git a/src/pipecat/services/sarvam/stt.py b/src/pipecat/services/sarvam/stt.py index e368ceb02..d8659a6e7 100644 --- a/src/pipecat/services/sarvam/stt.py +++ b/src/pipecat/services/sarvam/stt.py @@ -32,7 +32,13 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.sarvam._sdk import sdk_headers -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + STTSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.services.stt_latency import SARVAM_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -136,14 +142,13 @@ class SarvamSTTSettings(STTSettings): """Settings for the Sarvam STT service. Parameters: - prompt: Optional prompt to guide transcription/translation style. - mode: Mode of operation (transcribe, translate, verbatim, etc.). + prompt: Optional prompt to guide transcription/translation style/context. + Only applicable to models that support prompts (e.g., saaras:v2.5). vad_signals: Enable VAD signals in response. high_vad_sensitivity: Enable high VAD sensitivity. """ prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - mode: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) vad_signals: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) high_vad_sensitivity: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -171,6 +176,9 @@ class SarvamSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for Sarvam STT service. + .. deprecated:: 0.0.105 + Use ``settings=SarvamSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. - saarika:v2.5: Defaults to "unknown" (auto-detect supported) @@ -194,10 +202,14 @@ class SarvamSTTService(STTService): self, *, api_key: str, - model: str = "saarika:v2.5", + model: Optional[str] = None, + mode: Optional[ + Literal["transcribe", "translate", "verbatim", "translit", "codemix"] + ] = None, sample_rate: Optional[int] = None, input_audio_codec: str = "wav", params: Optional[InputParams] = None, + settings: Optional[SarvamSTTSettings] = None, ttfs_p99_latency: Optional[float] = SARVAM_TTFS_P99, keepalive_timeout: Optional[float] = None, keepalive_interval: float = 5.0, @@ -207,13 +219,23 @@ class SarvamSTTService(STTService): Args: api_key: Sarvam API key for authentication. - model: Sarvam model to use for transcription. Allowed values: - - "saarika:v2.5": Standard STT model - - "saaras:v2.5": STT-Translate model (auto-detects language, supports prompts) - - "saaras:v3": Advanced STT model (supports mode) + model: Sarvam model to use for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamSTTSettings(model=...)`` instead. + + mode: Mode of operation. Options: transcribe, translate, verbatim, + translit, codemix. Only applicable to models that support it + (e.g., saaras:v3). Defaults to the model's default mode. sample_rate: Audio sample rate. Defaults to 16000 if not specified. input_audio_codec: Audio codec/format of the input file. Defaults to "wav". params: Configuration parameters for Sarvam STT service. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark keepalive_timeout: Seconds of no audio before sending silence to keep the @@ -221,46 +243,71 @@ class SarvamSTTService(STTService): keepalive_interval: Seconds between idle checks when keepalive is enabled. **kwargs: Additional arguments passed to the parent STTService. """ - params = params or SarvamSTTService.InputParams() + # --- 1. Hardcoded defaults --- + default_settings = SarvamSTTSettings( + model="saarika:v2.5", + language=None, + prompt=None, + vad_signals=None, + high_vad_sensitivity=None, + ) - # Get model configuration (validates model exists) - if model not in MODEL_CONFIGS: + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", SarvamSTTSettings, "model") + default_settings.model = model + + # --- 3. Deprecated params overrides --- + if params is not None: + _warn_deprecated_param("params", SarvamSTTSettings) + if not settings: + default_settings.language = params.language + default_settings.prompt = params.prompt + if params.mode is not None: + mode = params.mode + default_settings.vad_signals = params.vad_signals + default_settings.high_vad_sensitivity = params.high_vad_sensitivity + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + + # Resolve model config and validate (after all overrides) + resolved_model = default_settings.model + if resolved_model not in MODEL_CONFIGS: allowed = ", ".join(sorted(MODEL_CONFIGS.keys())) - raise ValueError(f"Unsupported model '{model}'. Allowed values: {allowed}.") + raise ValueError(f"Unsupported model '{resolved_model}'. Allowed values: {allowed}.") - self._config = MODEL_CONFIGS[model] + self._config = MODEL_CONFIGS[resolved_model] # Validate parameters against model capabilities - if params.prompt is not None and not self._config.supports_prompt: - raise ValueError(f"Model '{model}' does not support prompt parameter.") - if params.mode is not None and not self._config.supports_mode: - raise ValueError(f"Model '{model}' does not support mode parameter.") - if params.language is not None and not self._config.supports_language: + if default_settings.prompt is not None and not self._config.supports_prompt: + raise ValueError(f"Model '{resolved_model}' does not support prompt parameter.") + if mode is not None and not self._config.supports_mode: + raise ValueError(f"Model '{resolved_model}' does not support mode parameter.") + if default_settings.language is not None and not self._config.supports_language: raise ValueError( - f"Model '{model}' does not support language parameter (auto-detects language)." + f"Model '{resolved_model}' does not support language parameter (auto-detects language)." ) # Resolve mode default from model config - mode = params.mode if params.mode is not None else self._config.default_mode + if mode is None: + mode = self._config.default_mode super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=keepalive_timeout, keepalive_interval=keepalive_interval, - settings=SarvamSTTSettings( - model=model, - language=params.language, - prompt=params.prompt, - mode=mode, - vad_signals=params.vad_signals, - high_vad_sensitivity=params.high_vad_sensitivity, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key + # Init-only connection config (not runtime-updatable) + self._mode = mode + # Store connection parameters self._input_audio_codec = input_audio_codec @@ -274,7 +321,7 @@ class SarvamSTTService(STTService): self._socket_client = None self._receive_task = None - if params.vad_signals: + if default_settings.vad_signals: self._register_event_handler("on_speech_started") self._register_event_handler("on_speech_stopped") self._register_event_handler("on_utterance_end") @@ -341,30 +388,26 @@ class SarvamSTTService(STTService): f"Model '{self._settings.model}' does not support language parameter " "(auto-detects language)." ) - - if isinstance(delta, SarvamSTTSettings): - if is_given(delta.prompt) and delta.prompt is not None: - if not self._config.supports_prompt: - raise ValueError( - f"Model '{self._settings.model}' does not support prompt parameter." - ) - if is_given(delta.mode) and delta.mode is not None: - if not self._config.supports_mode: - raise ValueError( - f"Model '{self._settings.model}' does not support mode parameter." - ) + if ( + isinstance(delta, SarvamSTTSettings) + and is_given(delta.prompt) + and delta.prompt is not None + ): + if not self._config.supports_prompt: + raise ValueError( + f"Model '{self._settings.model}' does not support prompt parameter." + ) changed = await super()._update_settings(delta) - # TODO: someday we could reconnect here to apply updated settings. - # Code might look something like the below: - # if not changed: - # return changed + # Prompt is a WebSocket connect-time parameter; reconnect to apply. + if "prompt" in changed: + await self._disconnect() + await self._connect() - # await self._disconnect() - # await self._connect() - - self._warn_unhandled_updated_settings(changed) + unhandled = {k: v for k, v in changed.items() if k != "prompt"} + if unhandled: + self._warn_unhandled_updated_settings(unhandled) return changed @@ -503,8 +546,8 @@ class SarvamSTTService(STTService): connect_kwargs["language_code"] = language_string # Add mode for models that support it - if self._config.supports_mode and self._settings.mode is not None: - connect_kwargs["mode"] = self._settings.mode + if self._config.supports_mode and self._mode is not None: + connect_kwargs["mode"] = self._mode # Prompt support differs across sarvamai versions. Prefer connect-time prompt # when available and gracefully degrade if the SDK doesn't accept it. diff --git a/src/pipecat/services/sarvam/tts.py b/src/pipecat/services/sarvam/tts.py index c18933407..0d605fc6b 100644 --- a/src/pipecat/services/sarvam/tts.py +++ b/src/pipecat/services/sarvam/tts.py @@ -62,7 +62,7 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.sarvam._sdk import sdk_headers -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -250,7 +250,6 @@ class SarvamHttpTTSSettings(TTSSettings): """Settings for Sarvam HTTP TTS service. Parameters: - language: Sarvam language code. enable_preprocessing: Whether to enable text preprocessing. Defaults to False. **Note:** Always enabled for bulbul:v3-beta (cannot be disabled). pace: Speech pace multiplier. Defaults to 1.0. @@ -263,60 +262,32 @@ class SarvamHttpTTSSettings(TTSSettings): temperature: Controls output randomness for bulbul:v3-beta (0.01 to 1.0). Lower values = more deterministic, higher = more random. Defaults to 0.6. **Note:** Only supported for bulbul:v3-beta. Ignored for v2. - sample_rate: Audio sample rate. """ - language: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) enable_preprocessing: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) pace: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) pitch: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) loudness: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) temperature: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - sarvam_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @dataclass -class SarvamTTSSettings(TTSSettings): +class SarvamTTSSettings(SarvamHttpTTSSettings): """Settings for Sarvam WebSocket TTS service. + Extends :class:`SarvamHttpTTSSettings` with WebSocket-specific buffering parameters. + Parameters: - language: Sarvam language code (e.g. ``"hi-IN"``). Uses the standard - ``TTSSettings.language`` field. - speech_sample_rate: Audio sample rate as string. - enable_preprocessing: Enable text preprocessing. Defaults to False. - **Note:** Always enabled for bulbul:v3-beta. min_buffer_size: Minimum characters to buffer before generating audio. Lower values reduce latency but may affect quality. Defaults to 50. max_chunk_length: Maximum characters processed in a single chunk. Controls memory usage and processing efficiency. Defaults to 150. - output_audio_codec: Audio codec format. Options: linear16, mulaw, alaw, - opus, flac, aac, wav, mp3. Defaults to "linear16". - output_audio_bitrate: Audio bitrate (32k, 64k, 96k, 128k, 192k). - Defaults to "128k". - pace: Speech pace multiplier. Defaults to 1.0. - - bulbul:v2: Range 0.3 to 3.0 - - bulbul:v3-beta: Range 0.5 to 2.0 - pitch: Voice pitch adjustment (-0.75 to 0.75). Defaults to 0.0. - **Note:** Only supported for bulbul:v2. Ignored for v3 models. - loudness: Volume multiplier (0.3 to 3.0). Defaults to 1.0. - **Note:** Only supported for bulbul:v2. Ignored for v3 models. - temperature: Controls output randomness for bulbul:v3-beta (0.01 to 1.0). - Lower = more deterministic, higher = more random. Defaults to 0.6. - **Note:** Only supported for bulbul:v3-beta. Ignored for v2. """ _aliases: ClassVar[Dict[str, str]] = {"target_language_code": "language"} - speech_sample_rate: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - enable_preprocessing: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) min_buffer_size: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) max_chunk_length: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_audio_codec: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - output_audio_bitrate: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - pace: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - pitch: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - loudness: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - temperature: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class SarvamHttpTTSService(TTSService): @@ -376,6 +347,9 @@ class SarvamHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Sarvam TTS configuration. + .. deprecated:: 0.0.105 + Use ``SarvamHttpTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English (India). pitch: Voice pitch adjustment (-0.75 to 0.75). Defaults to 0.0. @@ -428,10 +402,11 @@ class SarvamHttpTTSService(TTSService): api_key: str, aiohttp_session: aiohttp.ClientSession, voice_id: Optional[str] = None, - model: str = "bulbul:v2", + model: Optional[str] = None, base_url: str = "https://api.sarvam.ai", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[SarvamHttpTTSSettings] = None, **kwargs, ): """Initialize the Sarvam TTS service. @@ -440,59 +415,116 @@ class SarvamHttpTTSService(TTSService): api_key: Sarvam AI API subscription key. aiohttp_session: Shared aiohttp session for making requests. voice_id: Speaker voice ID. If None, uses model-appropriate default. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamHttpTTSSettings(voice=...)`` instead. + model: TTS model to use. Options: - "bulbul:v2" (default): Standard model with pitch/loudness support - "bulbul:v3-beta": Advanced model with temperature control + + .. deprecated:: 0.0.105 + Use ``settings=SarvamHttpTTSSettings(model=...)`` instead. + base_url: Sarvam AI API base URL. Defaults to "https://api.sarvam.ai". sample_rate: Audio sample rate in Hz (8000, 16000, 22050, 24000). If None, uses model-specific default. params: Additional voice and preprocessing parameters. If None, uses defaults. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - # Get model configuration (validates model exists) - if model not in TTS_MODEL_CONFIGS: - allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) - raise ValueError(f"Unsupported model '{model}'. Allowed values: {allowed}.") + # 1. Initialize default_settings with hardcoded defaults + default_settings = SarvamHttpTTSSettings( + model="bulbul:v2", + voice="anushka", + language="en-IN", + enable_preprocessing=False, + pace=1.0, + pitch=None, + loudness=None, + temperature=None, + ) - self._config = TTS_MODEL_CONFIGS[model] + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", SarvamHttpTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", SarvamHttpTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", SarvamHttpTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = ( + self.language_to_service_language(params.language) or "en-IN" + ) + if params.enable_preprocessing is not None: + default_settings.enable_preprocessing = params.enable_preprocessing + if params.pace is not None: + default_settings.pace = params.pace + if params.pitch is not None: + default_settings.pitch = params.pitch + if params.loudness is not None: + default_settings.loudness = params.loudness + if params.temperature is not None: + default_settings.temperature = params.temperature + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + # Get model configuration (validates model exists) + resolved_model = default_settings.model + if resolved_model not in TTS_MODEL_CONFIGS: + allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) + raise ValueError(f"Unsupported model '{resolved_model}'. Allowed values: {allowed}.") + + self._config = TTS_MODEL_CONFIGS[resolved_model] # Set default sample rate based on model if not specified if sample_rate is None: sample_rate = self._config.default_sample_rate - params = params or SarvamHttpTTSService.InputParams() - - # Set default voice based on model if not specified - if voice_id is None: - voice_id = self._config.default_speaker + # Set default voice based on model if not specified via any mechanism + if voice_id is None and (settings is None or settings.voice is NOT_GIVEN): + default_settings.voice = self._config.default_speaker # Validate and clamp pace to model's valid range - pace = params.pace + pace = default_settings.pace pace_min, pace_max = self._config.pace_range if pace is not None and (pace < pace_min or pace > pace_max): logger.warning(f"Pace {pace} is outside model range ({pace_min}-{pace_max}). Clamping.") - pace = max(pace_min, min(pace_max, pace)) + default_settings.pace = max(pace_min, min(pace_max, pace)) + + # Force preprocessing for models that require it + if self._config.preprocessing_always_enabled: + default_settings.enable_preprocessing = True + + # Warn about unsupported model-specific parameters + if not self._config.supports_pitch and default_settings.pitch not in (None, 0.0): + logger.warning(f"pitch parameter is ignored for {resolved_model}") + default_settings.pitch = None + if not self._config.supports_loudness and default_settings.loudness not in (None, 1.0): + logger.warning(f"loudness parameter is ignored for {resolved_model}") + default_settings.loudness = None + if not self._config.supports_temperature and default_settings.temperature not in ( + None, + 0.6, + ): + logger.warning(f"temperature parameter is ignored for {resolved_model}") + default_settings.temperature = None super().__init__( sample_rate=sample_rate, - settings=SarvamHttpTTSSettings( - language=( - self.language_to_service_language(params.language) - if params.language - else "en-IN" - ), - enable_preprocessing=( - True - if self._config.preprocessing_always_enabled - else params.enable_preprocessing - ), - pace=pace, - pitch=None, - loudness=None, - temperature=None, - model=model, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -500,22 +532,6 @@ class SarvamHttpTTSService(TTSService): self._base_url = base_url self._session = aiohttp_session - # Add parameters based on model support - if self._config.supports_pitch: - self._settings.pitch = params.pitch - elif params.pitch != 0.0: - logger.warning(f"pitch parameter is ignored for {model}") - - if self._config.supports_loudness: - self._settings.loudness = params.loudness - elif params.loudness != 1.0: - logger.warning(f"loudness parameter is ignored for {model}") - - if self._config.supports_temperature: - self._settings.temperature = params.temperature - elif params.temperature != 0.6: - logger.warning(f"temperature parameter is ignored for {model}") - def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -542,7 +558,6 @@ class SarvamHttpTTSService(TTSService): frame: The start frame containing initialization parameters. """ await super().start(frame) - self._settings.sarvam_sample_rate = self.sample_rate @traced_tts async def run_tts(self, text: str, context_id: str) -> AsyncGenerator[Frame, None]: @@ -697,6 +712,9 @@ class SarvamTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Configuration parameters for Sarvam TTS WebSocket service. + .. deprecated:: 0.0.105 + Use ``SarvamTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: pitch: Voice pitch adjustment (-0.75 to 0.75). Defaults to 0.0. **Note:** Only supported for bulbul:v2. Ignored for v3 models. @@ -782,13 +800,14 @@ class SarvamTTSService(InterruptibleTTSService): self, *, api_key: str, - model: str = "bulbul:v2", + model: Optional[str] = None, voice_id: Optional[str] = None, url: str = "wss://api.sarvam.ai/text-to-speech/ws", aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[SarvamTTSSettings] = None, **kwargs, ): """Initialize the Sarvam TTS service with voice and transport configuration. @@ -798,7 +817,15 @@ class SarvamTTSService(InterruptibleTTSService): model: TTS model to use. Options: - "bulbul:v2" (default): Standard model with pitch/loudness support - "bulbul:v3-beta": Advanced model with temperature control + + .. deprecated:: 0.0.105 + Use ``settings=SarvamTTSSettings(model=...)`` instead. + voice_id: Speaker voice ID. If None, uses model-appropriate default. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamTTSSettings(voice=...)`` instead. + url: WebSocket URL for the TTS backend (default production URL). aggregate_sentences: Deprecated. Use text_aggregation_mode instead. @@ -809,35 +836,115 @@ class SarvamTTSService(InterruptibleTTSService): sample_rate: Output audio sample rate in Hz (8000, 16000, 22050, 24000). If None, uses model-specific default. params: Optional input parameters to override defaults. + + .. deprecated:: 0.0.105 + Use ``settings=SarvamTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Arguments forwarded to InterruptibleTTSService. See https://docs.sarvam.ai/api-reference-docs/text-to-speech/stream """ - # Get model configuration (validates model exists) - if model not in TTS_MODEL_CONFIGS: - allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) - raise ValueError(f"Unsupported model '{model}'. Allowed values: {allowed}.") + # 1. Initialize default_settings with hardcoded defaults + default_settings = SarvamTTSSettings( + model="bulbul:v2", + voice="anushka", + language="en-IN", + enable_preprocessing=False, + min_buffer_size=50, + max_chunk_length=150, + pace=1.0, + pitch=None, + loudness=None, + temperature=None, + ) - self._config = TTS_MODEL_CONFIGS[model] + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", SarvamTTSSettings, "model") + default_settings.model = model + if voice_id is not None: + _warn_deprecated_param("voice_id", SarvamTTSSettings, "voice") + default_settings.voice = voice_id + + # Init-only audio format fields (not runtime-updatable) + output_audio_codec = "linear16" + output_audio_bitrate = "128k" + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", SarvamTTSSettings) + if not settings: + if params.language is not None: + default_settings.language = ( + self.language_to_service_language(params.language) or "en-IN" + ) + if params.enable_preprocessing is not None: + default_settings.enable_preprocessing = params.enable_preprocessing + if params.min_buffer_size is not None: + default_settings.min_buffer_size = params.min_buffer_size + if params.max_chunk_length is not None: + default_settings.max_chunk_length = params.max_chunk_length + if params.output_audio_codec is not None: + output_audio_codec = params.output_audio_codec + if params.output_audio_bitrate is not None: + output_audio_bitrate = params.output_audio_bitrate + if params.pace is not None: + default_settings.pace = params.pace + if params.pitch is not None: + default_settings.pitch = params.pitch + if params.loudness is not None: + default_settings.loudness = params.loudness + if params.temperature is not None: + default_settings.temperature = params.temperature + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + # Get model configuration (validates model exists) + resolved_model = default_settings.model + if resolved_model not in TTS_MODEL_CONFIGS: + allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) + raise ValueError(f"Unsupported model '{resolved_model}'. Allowed values: {allowed}.") + + self._config = TTS_MODEL_CONFIGS[resolved_model] # Set default sample rate based on model if not specified if sample_rate is None: sample_rate = self._config.default_sample_rate - # Set default voice based on model if not specified - if voice_id is None: - voice_id = self._config.default_speaker - - params = params or SarvamTTSService.InputParams() + # Set default voice based on model if not specified via any mechanism + if voice_id is None and (settings is None or settings.voice is NOT_GIVEN): + default_settings.voice = self._config.default_speaker # Validate and clamp pace to model's valid range - pace = params.pace + pace = default_settings.pace pace_min, pace_max = self._config.pace_range if pace is not None and (pace < pace_min or pace > pace_max): logger.warning(f"Pace {pace} is outside model range ({pace_min}-{pace_max}). Clamping.") - pace = max(pace_min, min(pace_max, pace)) + default_settings.pace = max(pace_min, min(pace_max, pace)) - # Initialize parent class first + # Force preprocessing for models that require it + if self._config.preprocessing_always_enabled: + default_settings.enable_preprocessing = True + + # Warn about unsupported model-specific parameters + if not self._config.supports_pitch and default_settings.pitch not in (None, 0.0): + logger.warning(f"pitch parameter is ignored for {resolved_model}") + default_settings.pitch = None + if not self._config.supports_loudness and default_settings.loudness not in (None, 1.0): + logger.warning(f"loudness parameter is ignored for {resolved_model}") + default_settings.loudness = None + if not self._config.supports_temperature and default_settings.temperature not in ( + None, + 0.6, + ): + logger.warning(f"temperature parameter is ignored for {resolved_model}") + default_settings.temperature = None + + # Initialize parent class super().__init__( aggregate_sentences=aggregate_sentences, text_aggregation_mode=text_aggregation_mode, @@ -845,52 +952,19 @@ class SarvamTTSService(InterruptibleTTSService): pause_frame_processing=True, push_stop_frames=True, sample_rate=sample_rate, - settings=SarvamTTSSettings( - language=( - self.language_to_service_language(params.language) - if params.language - else "en-IN" - ), - speech_sample_rate=str(sample_rate), - enable_preprocessing=( - True - if self._config.preprocessing_always_enabled - else params.enable_preprocessing - ), - min_buffer_size=params.min_buffer_size, - max_chunk_length=params.max_chunk_length, - output_audio_codec=params.output_audio_codec, - output_audio_bitrate=params.output_audio_bitrate, - pace=pace, - pitch=None, - loudness=None, - temperature=None, - model=model, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) + # Init-only audio format fields (not runtime-updatable) + self._speech_sample_rate = str(sample_rate) + self._output_audio_codec = output_audio_codec + self._output_audio_bitrate = output_audio_bitrate + # WebSocket endpoint URL with model query parameter - self._websocket_url = f"{url}?model={model}" + self._websocket_url = f"{url}?model={resolved_model}" self._api_key = api_key - # Add parameters based on model support - if self._config.supports_pitch: - self._settings.pitch = params.pitch - elif params.pitch != 0.0: - logger.warning(f"pitch parameter is ignored for {model}") - - if self._config.supports_loudness: - self._settings.loudness = params.loudness - elif params.loudness != 1.0: - logger.warning(f"loudness parameter is ignored for {model}") - - if self._config.supports_temperature: - self._settings.temperature = params.temperature - elif params.temperature != 0.6: - logger.warning(f"temperature parameter is ignored for {model}") - self._receive_task = None self._keepalive_task = None self._context_id: Optional[str] = None @@ -923,7 +997,7 @@ class SarvamTTSService(InterruptibleTTSService): await super().start(frame) # WebSocket API expects sample rate as string - self._settings.speech_sample_rate = str(self.sample_rate) + self._speech_sample_rate = str(self.sample_rate) await self._connect() async def stop(self, frame: EndFrame): @@ -1041,12 +1115,12 @@ class SarvamTTSService(InterruptibleTTSService): config_data = { "target_language_code": self._settings.language, "speaker": self._settings.voice, - "speech_sample_rate": self._settings.speech_sample_rate, + "speech_sample_rate": self._speech_sample_rate, "enable_preprocessing": self._settings.enable_preprocessing, "min_buffer_size": self._settings.min_buffer_size, "max_chunk_length": self._settings.max_chunk_length, - "output_audio_codec": self._settings.output_audio_codec, - "output_audio_bitrate": self._settings.output_audio_bitrate, + "output_audio_codec": self._output_audio_codec, + "output_audio_bitrate": self._output_audio_bitrate, "pace": self._settings.pace, "model": self._settings.model, } diff --git a/src/pipecat/services/settings.py b/src/pipecat/services/settings.py index 5d215273f..c9a120972 100644 --- a/src/pipecat/services/settings.py +++ b/src/pipecat/services/settings.py @@ -37,6 +37,7 @@ Key helpers: from __future__ import annotations import copy +import warnings from dataclasses import dataclass, field, fields from typing import TYPE_CHECKING, Any, ClassVar, Dict, Mapping, Optional, Type, TypeVar @@ -47,6 +48,46 @@ from pipecat.transcriptions.language import Language if TYPE_CHECKING: from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig + +# --------------------------------------------------------------------------- +# Deprecation helper +# --------------------------------------------------------------------------- + + +def _warn_deprecated_param( + param_name: str, + settings_class: type, + settings_field: str | None = None, + stacklevel: int = 3, +): + """Emit DeprecationWarning for a deprecated init parameter. + + Args: + param_name: Name of the deprecated parameter. + settings_class: The settings class to use instead. + settings_field: Specific field on the settings class, if different + from *param_name*. + stacklevel: Stack depth for the warning. Default ``3`` targets + the caller's caller (i.e. user code that instantiated the service). + """ + settings_class_name = settings_class.__name__ + if settings_field: + msg = ( + f"The `{param_name}` parameter is deprecated. " + f"Use `settings={settings_class_name}({settings_field}=...)` instead. " + f"If both are provided, `settings` takes precedence." + ) + else: + msg = ( + f"The `{param_name}` parameter is deprecated. " + f"Use `settings={settings_class_name}(...)` instead. " + f"If both are provided, `settings` takes precedence." + ) + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel) + + # --------------------------------------------------------------------------- # NOT_GIVEN sentinel # --------------------------------------------------------------------------- @@ -354,6 +395,7 @@ class LLMSettings(ServiceSettings): Parameters: model: LLM model identifier. + system_instruction: System instruction/prompt for the model. temperature: Sampling temperature. max_tokens: Maximum tokens to generate. top_p: Nucleus sampling probability. @@ -370,6 +412,7 @@ class LLMSettings(ServiceSettings): and prompts for incomplete turns. """ + system_instruction: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) temperature: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) max_tokens: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) top_p: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) diff --git a/src/pipecat/services/soniox/stt.py b/src/pipecat/services/soniox/stt.py index 32cbee1f4..483cad062 100644 --- a/src/pipecat/services/soniox/stt.py +++ b/src/pipecat/services/soniox/stt.py @@ -24,7 +24,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import SONIOX_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language @@ -79,6 +79,9 @@ class SonioxContextObject(BaseModel): class SonioxInputParams(BaseModel): """Real-time transcription settings. + .. deprecated:: 0.0.105 + Use ``settings=SonioxSTTSettings(...)`` instead. + See Soniox WebSocket API documentation for more details: https://soniox.com/docs/speech-to-text/api-reference/websocket-api#configuration-parameters @@ -141,8 +144,6 @@ class SonioxSTTSettings(STTSettings): """Settings for Soniox STT service. Parameters: - audio_format: Audio format to use for transcription. - num_channels: Number of channels to use for transcription. language_hints: List of language hints to use for transcription. language_hints_strict: If true, strictly enforce language hints. context: Customization for transcription. String for models with @@ -153,8 +154,6 @@ class SonioxSTTSettings(STTSettings): client_reference_id: Client reference ID to use for transcription. """ - audio_format: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - num_channels: int | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) language_hints: List[Language] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) language_hints_strict: bool | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) context: SonioxContextObject | str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -183,8 +182,12 @@ class SonioxSTTService(WebsocketSTTService): api_key: str, url: str = "wss://stt-rt.soniox.com/transcribe-websocket", sample_rate: Optional[int] = None, + model: Optional[str] = None, + audio_format: str = "pcm_s16le", + num_channels: int = 1, params: Optional[SonioxInputParams] = None, vad_force_turn_endpoint: bool = True, + settings: Optional[SonioxSTTSettings] = None, ttfs_p99_latency: Optional[float] = SONIOX_TTFS_P99, **kwargs, ): @@ -194,33 +197,72 @@ class SonioxSTTService(WebsocketSTTService): api_key: Soniox API key. url: Soniox WebSocket API URL. sample_rate: Audio sample rate. + model: Soniox model to use for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=SonioxSTTSettings(model=...)`` instead. + + audio_format: Audio format for transcription. Defaults to ``"pcm_s16le"``. + num_channels: Number of audio channels. Defaults to 1. params: Additional configuration parameters, such as language hints, context and speaker diarization. + + .. deprecated:: 0.0.105 + Use ``settings=SonioxSTTSettings(...)`` instead. + vad_force_turn_endpoint: Listen to `VADUserStoppedSpeakingFrame` to send finalize message to Soniox. If disabled, Soniox will detect the end of the speech. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService. """ - params = params or SonioxInputParams() + # --- 1. Hardcoded defaults --- + default_settings = SonioxSTTSettings( + model="stt-rt-v4", + language=None, + language_hints=None, + language_hints_strict=None, + context=None, + enable_speaker_diarization=False, + enable_language_identification=False, + client_reference_id=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", SonioxSTTSettings, "model") + default_settings.model = model + + # --- 3. Deprecated params overrides --- + if params is not None: + _warn_deprecated_param("params", SonioxSTTSettings) + if not settings: + default_settings.model = params.model + if params.audio_format is not None: + audio_format = params.audio_format + if params.num_channels is not None: + num_channels = params.num_channels + default_settings.language_hints = params.language_hints + default_settings.language_hints_strict = params.language_hints_strict + default_settings.context = params.context + default_settings.enable_speaker_diarization = params.enable_speaker_diarization + default_settings.enable_language_identification = ( + params.enable_language_identification + ) + default_settings.client_reference_id = params.client_reference_id + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=1, keepalive_interval=5, - settings=SonioxSTTSettings( - model=params.model, - language=None, - audio_format=params.audio_format, - num_channels=params.num_channels, - language_hints=params.language_hints, - language_hints_strict=params.language_hints_strict, - context=params.context, - enable_speaker_diarization=params.enable_speaker_diarization, - enable_language_identification=params.enable_language_identification, - client_reference_id=params.client_reference_id, - ), + settings=default_settings, **kwargs, ) @@ -228,6 +270,10 @@ class SonioxSTTService(WebsocketSTTService): self._url = url self._vad_force_turn_endpoint = vad_force_turn_endpoint + # Init-only audio config + self._audio_format = audio_format + self._num_channels = num_channels + self._final_transcription_buffer = [] self._last_tokens_received: Optional[float] = None @@ -396,8 +442,8 @@ class SonioxSTTService(WebsocketSTTService): config = { "api_key": self._api_key, "model": s.model, - "audio_format": s.audio_format, - "num_channels": s.num_channels or 1, + "audio_format": self._audio_format, + "num_channels": self._num_channels, "enable_endpoint_detection": enable_endpoint_detection, "sample_rate": self.sample_rate, "language_hints": _prepare_language_hints(s.language_hints), diff --git a/src/pipecat/services/speechmatics/stt.py b/src/pipecat/services/speechmatics/stt.py index bdeb3b249..b3ded9255 100644 --- a/src/pipecat/services/speechmatics/stt.py +++ b/src/pipecat/services/speechmatics/stt.py @@ -33,7 +33,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import SPEECHMATICS_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -100,7 +100,6 @@ class SpeechmaticsSTTSettings(STTSettings): focus_mode: Speaker focus mode for diarization. known_speakers: List of known speaker labels and identifiers. additional_vocab: List of additional vocabulary entries. - audio_encoding: Audio encoding format. operating_point: Operating point for accuracy vs. latency. max_delay: Maximum delay in seconds for transcription. end_of_utterance_silence_trigger: Maximum delay for end of utterance trigger. @@ -126,7 +125,6 @@ class SpeechmaticsSTTSettings(STTSettings): additional_vocab: list[AdditionalVocabEntry] | _NotGiven = field( default_factory=lambda: NOT_GIVEN ) - audio_encoding: AudioEncoding | _NotGiven = field(default_factory=lambda: NOT_GIVEN) operating_point: OperatingPoint | _NotGiven = field(default_factory=lambda: NOT_GIVEN) max_delay: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) end_of_utterance_silence_trigger: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -344,8 +342,8 @@ class SpeechmaticsSTTService(STTService): class UpdateParams(BaseModel): """Update parameters for Speechmatics STT service. - These are the only parameters that can be changed once a session has started. If you need to - change the language, etc., then you must create a new instance of the service. + .. deprecated:: 0.0.104 + Use ``SpeechmaticsSTTSettings`` with ``STTUpdateSettingsFrame`` instead. Parameters: focus_speakers: List of speaker IDs to focus on. When enabled, only these speakers are @@ -379,8 +377,10 @@ class SpeechmaticsSTTService(STTService): api_key: str | None = None, base_url: str | None = None, sample_rate: int | None = None, + encoding: AudioEncoding = AudioEncoding.PCM_S16LE, params: InputParams | None = None, should_interrupt: bool = True, + settings: SpeechmaticsSTTSettings | None = None, ttfs_p99_latency: float | None = SPEECHMATICS_TTFS_P99, **kwargs, ): @@ -392,8 +392,15 @@ class SpeechmaticsSTTService(STTService): base_url: Base URL for Speechmatics API. Uses environment variable `SPEECHMATICS_RT_URL` or defaults to `wss://eu2.rt.speechmatics.com/v2`. sample_rate: Optional audio sample rate in Hz. - params: Optional[InputParams]: Input parameters for the service. + encoding: Audio encoding format. Defaults to ``AudioEncoding.PCM_S16LE``. + params: Input parameters for the service. + + .. deprecated:: 0.0.105 + Use ``settings=SpeechmaticsSTTSettings(...)`` instead. + should_interrupt: Determine whether the bot should be interrupted when Speechmatics turn_detection_mode is configured to detect user speech. + settings: Runtime-updatable settings. When provided alongside deprecated + ``params``, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. @@ -410,58 +417,93 @@ class SpeechmaticsSTTService(STTService): if not self._base_url: raise ValueError("Missing Speechmatics base URL") - # Default params - params = params or SpeechmaticsSTTService.InputParams() self._should_interrupt = should_interrupt - # Deprecation check - self._check_deprecated_args(kwargs, params) + # Deprecation check (mutates params in-place for legacy kwargs migration) + _params = params or SpeechmaticsSTTService.InputParams() + self._check_deprecated_args(kwargs, _params) - # Output formatting defaults - speaker_active_format = params.speaker_active_format - if speaker_active_format is None: - speaker_active_format = ( - "@{speaker_id}: {text}" if params.enable_diarization else "{text}" - ) - speaker_passive_format = params.speaker_passive_format or speaker_active_format - - # Settings — seeded from InputParams - settings = SpeechmaticsSTTSettings( + # --- 1. Hardcoded defaults --- + default_settings = SpeechmaticsSTTSettings( model=None, # Will be resolved from operating_point after config is built - language=params.language, - domain=params.domain, - turn_detection_mode=params.turn_detection_mode, - speaker_active_format=speaker_active_format, - speaker_passive_format=speaker_passive_format, - focus_speakers=params.focus_speakers, - ignore_speakers=params.ignore_speakers, - focus_mode=params.focus_mode, - known_speakers=params.known_speakers, - additional_vocab=params.additional_vocab, - audio_encoding=params.audio_encoding, - operating_point=params.operating_point, - max_delay=params.max_delay, - end_of_utterance_silence_trigger=params.end_of_utterance_silence_trigger, - end_of_utterance_max_delay=params.end_of_utterance_max_delay, - punctuation_overrides=params.punctuation_overrides, - include_partials=params.include_partials, - split_sentences=params.split_sentences, - enable_diarization=params.enable_diarization, - speaker_sensitivity=params.speaker_sensitivity, - max_speakers=params.max_speakers, - prefer_current_speaker=params.prefer_current_speaker, - extra_params=params.extra_params, + language=Language.EN, + domain=None, + turn_detection_mode=TurnDetectionMode.EXTERNAL, + speaker_active_format="{text}", + speaker_passive_format="{text}", + focus_speakers=[], + ignore_speakers=[], + focus_mode=SpeakerFocusMode.RETAIN, + known_speakers=[], + additional_vocab=[], + operating_point=None, + max_delay=None, + end_of_utterance_silence_trigger=None, + end_of_utterance_max_delay=None, + punctuation_overrides=None, + include_partials=None, + split_sentences=None, + enable_diarization=None, + speaker_sensitivity=None, + max_speakers=None, + prefer_current_speaker=None, + extra_params=None, ) + # --- 2. No direct init arg overrides --- + + # --- 3. Deprecated params overrides --- + if params is not None: + _warn_deprecated_param("params", SpeechmaticsSTTSettings) + if not settings: + default_settings.language = _params.language + default_settings.domain = _params.domain + default_settings.turn_detection_mode = _params.turn_detection_mode + # Output formatting defaults + speaker_active_format = _params.speaker_active_format + if speaker_active_format is None: + speaker_active_format = ( + "@{speaker_id}: {text}" if _params.enable_diarization else "{text}" + ) + default_settings.speaker_active_format = speaker_active_format + default_settings.speaker_passive_format = ( + _params.speaker_passive_format or speaker_active_format + ) + default_settings.focus_speakers = _params.focus_speakers + default_settings.ignore_speakers = _params.ignore_speakers + default_settings.focus_mode = _params.focus_mode + default_settings.known_speakers = _params.known_speakers + default_settings.additional_vocab = _params.additional_vocab + encoding = _params.audio_encoding + default_settings.operating_point = _params.operating_point + default_settings.max_delay = _params.max_delay + default_settings.end_of_utterance_silence_trigger = ( + _params.end_of_utterance_silence_trigger + ) + default_settings.end_of_utterance_max_delay = _params.end_of_utterance_max_delay + default_settings.punctuation_overrides = _params.punctuation_overrides + default_settings.include_partials = _params.include_partials + default_settings.split_sentences = _params.split_sentences + default_settings.enable_diarization = _params.enable_diarization + default_settings.speaker_sensitivity = _params.speaker_sensitivity + default_settings.max_speakers = _params.max_speakers + default_settings.prefer_current_speaker = _params.prefer_current_speaker + default_settings.extra_params = _params.extra_params + # Build SDK config from settings, then resolve model from operating_point self._client: VoiceAgentClient | None = None - self._config: VoiceAgentConfig = self._build_config(settings) - settings.model = self._config.operating_point.value + self._audio_encoding = encoding + self._config: VoiceAgentConfig = self._build_config(default_settings) + default_settings.model = self._config.operating_point.value + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) @@ -483,7 +525,7 @@ class SpeechmaticsSTTService(STTService): self._bot_speaking: bool = False # Event handlers - if params.enable_diarization: + if default_settings.enable_diarization: self._register_event_handler("on_speakers_result") # ============================================================================ @@ -678,6 +720,9 @@ class SpeechmaticsSTTService(STTService): # Preset from turn detection mode config = VoiceAgentConfigPreset.load(s.turn_detection_mode.value) + # Audio encoding (init-only, stored as instance attribute) + config.audio_encoding = self._audio_encoding + # Language + domain language = s.language config.language = self._language_to_speechmatics_language(language) @@ -731,7 +776,7 @@ class SpeechmaticsSTTService(STTService): ) -> None: """Updates the speaker configuration. - .. deprecated:: + .. deprecated:: 0.0.104 Use ``STTUpdateSettingsFrame`` with ``SpeechmaticsSTTSettings(...)`` instead. diff --git a/src/pipecat/services/speechmatics/tts.py b/src/pipecat/services/speechmatics/tts.py index 1ddb895aa..55ded437e 100644 --- a/src/pipecat/services/speechmatics/tts.py +++ b/src/pipecat/services/speechmatics/tts.py @@ -22,7 +22,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.network import exponential_backoff_time from pipecat.utils.tracing.service_decorators import traced_tts @@ -62,6 +62,9 @@ class SpeechmaticsTTSService(TTSService): class InputParams(BaseModel): """Optional input parameters for Speechmatics TTS configuration. + .. deprecated:: 0.0.105 + Use ``settings=SpeechmaticsTTSSettings(...)`` instead. + Parameters: max_retries: Maximum number of retries for TTS requests. Defaults to 5. """ @@ -73,10 +76,11 @@ class SpeechmaticsTTSService(TTSService): *, api_key: str, base_url: str = "https://preview.tts.speechmatics.com", - voice_id: str = "sarah", + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, sample_rate: Optional[int] = SPEECHMATICS_SAMPLE_RATE, params: Optional[InputParams] = None, + settings: Optional[SpeechmaticsTTSSettings] = None, **kwargs, ): """Initialize the Speechmatics TTS service. @@ -85,9 +89,19 @@ class SpeechmaticsTTSService(TTSService): api_key: Speechmatics API key for authentication. base_url: Base URL for Speechmatics TTS API. voice_id: Voice model to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=SpeechmaticsTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. sample_rate: Audio sample rate in Hz. - params: Optional[InputParams]: Input parameters for the service. + params: Input parameters for the service. + + .. deprecated:: 0.0.105 + Use ``settings=SpeechmaticsTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to TTSService. """ if sample_rate and sample_rate != self.SPEECHMATICS_SAMPLE_RATE: @@ -95,16 +109,33 @@ class SpeechmaticsTTSService(TTSService): f"Speechmatics TTS only supports {self.SPEECHMATICS_SAMPLE_RATE}Hz sample rate. " f"Current rate of {sample_rate}Hz may cause issues." ) - params = params or SpeechmaticsTTSService.InputParams() + + # 1. Initialize default_settings with hardcoded defaults + default_settings = SpeechmaticsTTSSettings( + model=None, + voice="sarah", + language=None, + max_retries=5, + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", SpeechmaticsTTSSettings, "voice") + default_settings.voice = voice_id + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", SpeechmaticsTTSSettings) + if not settings: + default_settings.max_retries = params.max_retries + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=SpeechmaticsTTSSettings( - model=None, - voice=voice_id, - language=None, - max_retries=params.max_retries, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/tavus/video.py b/src/pipecat/services/tavus/video.py index 8c63ff354..4a7211033 100644 --- a/src/pipecat/services/tavus/video.py +++ b/src/pipecat/services/tavus/video.py @@ -11,6 +11,7 @@ avatar functionality through Tavus's streaming API. """ import asyncio +from dataclasses import dataclass from typing import Optional import aiohttp @@ -34,9 +35,17 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection, FrameProcessorSetup from pipecat.services.ai_service import AIService +from pipecat.services.settings import ServiceSettings from pipecat.transports.tavus.transport import TavusCallbacks, TavusParams, TavusTransportClient +@dataclass +class TavusVideoSettings(ServiceSettings): + """Settings for the Tavus video service.""" + + pass + + class TavusVideoService(AIService): """Service that proxies audio to Tavus and receives audio and video in return. @@ -57,6 +66,7 @@ class TavusVideoService(AIService): replica_id: str, persona_id: str = "pipecat-stream", session: aiohttp.ClientSession, + settings: Optional[TavusVideoSettings] = None, **kwargs, ) -> None: """Initialize the Tavus video service. @@ -66,9 +76,15 @@ class TavusVideoService(AIService): replica_id: ID of the Tavus voice replica to use for speech synthesis. persona_id: ID of the Tavus persona. Defaults to "pipecat-stream" for Pipecat TTS voice. session: Async HTTP session used for communication with Tavus. + settings: Runtime-updatable settings. Tavus has no model concept, so this + is primarily used for the ``extra`` dict. **kwargs: Additional arguments passed to the parent AIService class. """ - super().__init__(**kwargs) + default_settings = ServiceSettings(model=None) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._api_key = api_key self._session = session self._replica_id = replica_id diff --git a/src/pipecat/services/together/llm.py b/src/pipecat/services/together/llm.py index 277e8bc9c..2fa952a95 100644 --- a/src/pipecat/services/together/llm.py +++ b/src/pipecat/services/together/llm.py @@ -6,9 +6,21 @@ """Together.ai LLM service implementation using OpenAI-compatible interface.""" +from dataclasses import dataclass +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param + + +@dataclass +class TogetherLLMSettings(OpenAILLMSettings): + """Settings for Together LLM service.""" + + pass class TogetherLLMService(OpenAILLMService): @@ -18,12 +30,15 @@ class TogetherLLMService(OpenAILLMService): maintaining full compatibility with OpenAI's interface and functionality. """ + _settings: TogetherLLMSettings + def __init__( self, *, api_key: str, base_url: str = "https://api.together.xyz/v1", - model: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", + model: Optional[str] = None, + settings: Optional[TogetherLLMSettings] = None, **kwargs, ): """Initialize Together.ai LLM service. @@ -32,9 +47,27 @@ class TogetherLLMService(OpenAILLMService): api_key: The API key for accessing Together.ai's API. base_url: The base URL for Together.ai API. Defaults to "https://api.together.xyz/v1". model: The model identifier to use. Defaults to "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo". + + .. deprecated:: 0.0.105 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + # 1. Initialize default_settings with hardcoded defaults + default_settings = TogetherLLMSettings(model="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo") + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", TogetherLLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Together.ai API endpoint. diff --git a/src/pipecat/services/ultravox/llm.py b/src/pipecat/services/ultravox/llm.py index 07c3c34fe..eccc1a864 100644 --- a/src/pipecat/services/ultravox/llm.py +++ b/src/pipecat/services/ultravox/llm.py @@ -172,32 +172,44 @@ class UltravoxRealtimeLLMService(LLMService): self, *, params: Union[AgentInputParams, OneShotInputParams, JoinUrlInputParams], + settings: Optional[UltravoxRealtimeLLMSettings] = None, one_shot_selected_tools: Optional[ToolsSchema] = None, **kwargs, ): """Initialize the Ultravox Realtime LLM service. Args: - api_key: Ultravox API key for authentication. params: Configuration parameters for the model. + settings: Ultravox Realtime LLM settings. If provided, the ``settings`` + values take precedence over default values. one_shot_selected_tools: ToolsSchema for tools to use with this call. May only be set with OneShotInputParams. **kwargs: Additional arguments passed to parent LLMService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = UltravoxRealtimeLLMSettings( + model=None, + system_instruction=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + output_medium=None, + ) + + # (No step 2/3 — params is required and not deprecated) + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=UltravoxRealtimeLLMSettings( - model=None, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - output_medium=None, - ), + settings=default_settings, **kwargs, ) self._params = params diff --git a/src/pipecat/services/whisper/base_stt.py b/src/pipecat/services/whisper/base_stt.py index 08310831c..13de0f251 100644 --- a/src/pipecat/services/whisper/base_stt.py +++ b/src/pipecat/services/whisper/base_stt.py @@ -11,14 +11,14 @@ interface, including language mapping, metrics generation, and error handling. """ from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, Optional +from typing import AsyncGenerator, Optional from loguru import logger from openai import AsyncOpenAI from openai.types.audio import Transcription from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import WHISPER_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -31,15 +31,13 @@ class BaseWhisperSTTSettings(STTSettings): """Settings for Whisper API-based STT services. Parameters: - base_url: API base URL. prompt: Optional text to guide the model's style or continue a previous segment. temperature: Sampling temperature between 0 and 1. """ - base_url: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - prompt: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - temperature: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + prompt: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + temperature: float | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN) def language_to_whisper_language(language: Language) -> Optional[str]: @@ -129,14 +127,15 @@ class BaseWhisperSTTService(SegmentedSTTService): def __init__( self, *, - model: str, + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, include_prob_metrics: bool = False, push_empty_transcripts: bool = False, + settings: Optional[BaseWhisperSTTSettings] = None, ttfs_p99_latency: Optional[float] = WHISPER_TTFS_P99, **kwargs, ): @@ -144,11 +143,27 @@ class BaseWhisperSTTService(SegmentedSTTService): Args: model: Name of the Whisper model to use. + + .. deprecated:: 0.0.105 + Use ``settings=BaseWhisperSTTSettings(model=...)`` instead. + api_key: Service API key. Defaults to None. base_url: Service API base URL. Defaults to None. - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 0.0.105 + Use ``settings=BaseWhisperSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 0.0.105 + Use ``settings=BaseWhisperSTTSettings(prompt=...)`` instead. + + temperature: Sampling temperature between 0 and 1. + + .. deprecated:: 0.0.105 + Use ``settings=BaseWhisperSTTSettings(temperature=...)`` instead. + include_prob_metrics: If True, enables probability metrics in API response. Each service implements this differently (see child classes). Defaults to False. @@ -158,48 +173,52 @@ class BaseWhisperSTTService(SegmentedSTTService): useful to know that nothing was transcribed so that the agent can resume speaking, instead of waiting longer for a transcription. Defaults to False. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ + # --- 1. Hardcoded defaults --- + default_settings = BaseWhisperSTTSettings( + model=None, + language=None, + prompt=None, + temperature=None, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", BaseWhisperSTTSettings, "model") + default_settings.model = model + if language is not None: + _warn_deprecated_param("language", BaseWhisperSTTSettings, "language") + default_settings.language = self.language_to_service_language(language) + if prompt is not None: + _warn_deprecated_param("prompt", BaseWhisperSTTSettings, "prompt") + default_settings.prompt = prompt + if temperature is not None: + _warn_deprecated_param("temperature", BaseWhisperSTTSettings, "temperature") + default_settings.temperature = temperature + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( ttfs_p99_latency=ttfs_p99_latency, - settings=BaseWhisperSTTSettings( - model=model, - language=self.language_to_service_language(language or Language.EN), - base_url=base_url, - prompt=prompt, - temperature=temperature, - ), + settings=default_settings, **kwargs, ) self._client = self._create_client(api_key, base_url) - self._language = self._settings.language - self._prompt = prompt - self._temperature = temperature self._include_prob_metrics = include_prob_metrics self._push_empty_transcripts = push_empty_transcripts def _create_client(self, api_key: Optional[str], base_url: Optional[str]): return AsyncOpenAI(api_key=api_key, base_url=base_url) - async def _update_settings(self, delta: STTSettings) -> dict[str, Any]: - """Apply a settings delta, syncing instance variables. - - Keeps ``_language``, ``_prompt``, and ``_temperature`` in sync with - the settings fields. - """ - changed = await super()._update_settings(delta) - - if "language" in changed: - self._language = self._settings.language - if "prompt" in changed: - self._prompt = self._settings.prompt - if "temperature" in changed: - self._temperature = self._settings.temperature - - return changed - def can_generate_metrics(self) -> bool: """Whether this service can generate processing metrics. @@ -249,7 +268,7 @@ class BaseWhisperSTTService(SegmentedSTTService): logger.warning("Received empty transcription from API") if text or self._push_empty_transcripts: - await self._handle_transcription(text, True, self._language) + await self._handle_transcription(text, True, self._settings.language) logger.debug(f"Transcription: [{text}]") yield TranscriptionFrame( text, diff --git a/src/pipecat/services/whisper/stt.py b/src/pipecat/services/whisper/stt.py index d386d6ed2..af96f92c0 100644 --- a/src/pipecat/services/whisper/stt.py +++ b/src/pipecat/services/whisper/stt.py @@ -20,7 +20,7 @@ from loguru import logger from typing_extensions import TYPE_CHECKING, override from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.time import time_now_iso8601 @@ -179,13 +179,9 @@ class WhisperSTTSettings(STTSettings): """Settings for the local Whisper (Faster Whisper) STT service. Parameters: - device: Inference device ('cpu', 'cuda', or 'auto'). - compute_type: Compute type for inference ('default', 'int8', etc.). no_speech_prob: Probability threshold for filtering non-speech segments. """ - device: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) - compute_type: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) no_speech_prob: float | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @@ -216,36 +212,73 @@ class WhisperSTTService(SegmentedSTTService): def __init__( self, *, - model: str | Model = Model.DISTIL_MEDIUM_EN, + model: Optional[str | Model] = None, device: str = "auto", compute_type: str = "default", - no_speech_prob: float = 0.4, - language: Language = Language.EN, + no_speech_prob: Optional[float] = None, + language: Optional[Language] = None, + settings: Optional[WhisperSTTSettings] = None, **kwargs, ): """Initialize the Whisper STT service. Args: model: The Whisper model to use for transcription. Can be a Model enum or string. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperSTTSettings(model=...)`` instead. + device: The device to run inference on ('cpu', 'cuda', or 'auto'). - compute_type: The compute type for inference ('default', 'int8', 'int8_float16', etc.). + Defaults to ``"auto"``. + compute_type: The compute type for inference ('default', 'int8', + 'int8_float16', etc.). Defaults to ``"default"``. no_speech_prob: Probability threshold for filtering out non-speech segments. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperSTTSettings(no_speech_prob=...)`` instead. + language: The default language for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperSTTSettings(language=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to SegmentedSTTService. """ + # --- 1. Hardcoded defaults --- + default_settings = WhisperSTTSettings( + model=Model.DISTIL_MEDIUM_EN.value, + language=Language.EN, + no_speech_prob=0.4, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", WhisperSTTSettings, "model") + default_settings.model = model if isinstance(model, str) else model.value + if no_speech_prob is not None: + _warn_deprecated_param("no_speech_prob", WhisperSTTSettings, "no_speech_prob") + default_settings.no_speech_prob = no_speech_prob + if language is not None: + _warn_deprecated_param("language", WhisperSTTSettings, "language") + default_settings.language = language + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=WhisperSTTSettings( - model=model if isinstance(model, str) else model.value, - language=language, - device=device, - compute_type=compute_type, - no_speech_prob=no_speech_prob, - ), + settings=default_settings, **kwargs, ) - self._device: str = device + + # Init-only inference config + self._device = device self._compute_type = compute_type - self._no_speech_prob = no_speech_prob + self._model: Optional[WhisperModel] = None self._load() @@ -324,7 +357,7 @@ class WhisperSTTService(SegmentedSTTService): ) text: str = "" for segment in segments: - if segment.no_speech_prob < self._no_speech_prob: + if segment.no_speech_prob < self._settings.no_speech_prob: text += f"{segment.text} " await self.stop_processing_metrics() @@ -352,37 +385,76 @@ class WhisperSTTServiceMLX(WhisperSTTService): def __init__( self, *, - model: str | MLXModel = MLXModel.TINY, - no_speech_prob: float = 0.6, - language: Language = Language.EN, - temperature: float = 0.0, + model: Optional[str | MLXModel] = None, + no_speech_prob: Optional[float] = None, + language: Optional[Language] = None, + temperature: Optional[float] = None, + settings: Optional[WhisperMLXSTTSettings] = None, **kwargs, ): """Initialize the MLX Whisper STT service. Args: model: The MLX Whisper model to use for transcription. Can be an MLXModel enum or string. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperMLXSTTSettings(model=...)`` instead. + no_speech_prob: Probability threshold for filtering out non-speech segments. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperMLXSTTSettings(no_speech_prob=...)`` instead. + language: The default language for transcription. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperMLXSTTSettings(language=...)`` instead. + temperature: Temperature for sampling. Can be a float or tuple of floats. + + .. deprecated:: 0.0.105 + Use ``settings=WhisperMLXSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to SegmentedSTTService. """ + # --- 1. Hardcoded defaults --- + default_settings = WhisperMLXSTTSettings( + model=MLXModel.TINY.value, + language=Language.EN, + no_speech_prob=0.6, + temperature=0.0, + engine="mlx", + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", WhisperMLXSTTSettings, "model") + default_settings.model = model if isinstance(model, str) else model.value + if no_speech_prob is not None: + _warn_deprecated_param("no_speech_prob", WhisperMLXSTTSettings, "no_speech_prob") + default_settings.no_speech_prob = no_speech_prob + if language is not None: + _warn_deprecated_param("language", WhisperMLXSTTSettings, "language") + default_settings.language = language + if temperature is not None: + _warn_deprecated_param("temperature", WhisperMLXSTTSettings, "temperature") + default_settings.temperature = temperature + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- + if settings is not None: + default_settings.apply_update(settings) + # Skip WhisperSTTService.__init__ and call its parent directly SegmentedSTTService.__init__( self, - settings=WhisperMLXSTTSettings( - model=model if isinstance(model, str) else model.value, - language=language, - no_speech_prob=no_speech_prob, - temperature=temperature, - engine="mlx", - ), + settings=default_settings, **kwargs, ) - self._no_speech_prob = no_speech_prob - self._temperature = temperature - # No need to call _load() as MLX Whisper loads models on demand @override @@ -423,7 +495,7 @@ class WhisperSTTServiceMLX(WhisperSTTService): mlx_whisper.transcribe, audio_float, path_or_hf_repo=self._settings.model, - temperature=self._temperature, + temperature=self._settings.temperature, language=self._settings.language, ) text: str = "" @@ -432,7 +504,7 @@ class WhisperSTTServiceMLX(WhisperSTTService): if segment.get("compression_ratio", None) == 0.5555555555555556: continue - if segment.get("no_speech_prob", 0.0) < self._no_speech_prob: + if segment.get("no_speech_prob", 0.0) < self._settings.no_speech_prob: text += f"{segment.get('text', '')} " if len(text.strip()) == 0: diff --git a/src/pipecat/services/xtts/tts.py b/src/pipecat/services/xtts/tts.py index 8817c09b5..ea7cb0b8b 100644 --- a/src/pipecat/services/xtts/tts.py +++ b/src/pipecat/services/xtts/tts.py @@ -10,7 +10,7 @@ This module provides integration with Coqui XTTS streaming server for text-to-speech synthesis using local Docker deployment. """ -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import AsyncGenerator, Dict, Optional import aiohttp @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -72,13 +72,9 @@ def language_to_xtts_language(language: Language) -> Optional[str]: @dataclass class XTTSTTSSettings(TTSSettings): - """Settings for XTTS TTS service. + """Settings for XTTS TTS service.""" - Parameters: - base_url: Base URL of the XTTS streaming server. - """ - - base_url: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) + pass class XTTSService(TTSService): @@ -94,33 +90,55 @@ class XTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, base_url: str, aiohttp_session: aiohttp.ClientSession, language: Language = Language.EN, sample_rate: Optional[int] = None, + settings: Optional[XTTSTTSSettings] = None, **kwargs, ): """Initialize the XTTS service. Args: voice_id: ID of the voice/speaker to use for synthesis. + + .. deprecated:: 0.0.105 + Use ``settings=XTTSTTSSettings(voice=...)`` instead. + base_url: Base URL of the XTTS streaming server. aiohttp_session: HTTP session for making requests to the server. language: Language for synthesis. Defaults to English. sample_rate: Audio sample rate. If None, uses default. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = XTTSTTSSettings( + model=None, + voice=None, + language=self.language_to_service_language(language), + ) + + # 2. Apply direct init arg overrides (deprecated) + if voice_id is not None: + _warn_deprecated_param("voice_id", XTTSTTSSettings, "voice") + default_settings.voice = voice_id + + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, - settings=XTTSTTSSettings( - model=None, - voice=voice_id, - language=self.language_to_service_language(language), - base_url=base_url, - ), + settings=default_settings, **kwargs, ) + + # Init-only fields (not runtime-updatable) + self._base_url = base_url + self._studio_speakers: Optional[Dict[str, Any]] = None self._aiohttp_session = aiohttp_session @@ -156,7 +174,7 @@ class XTTSService(TTSService): if self._studio_speakers: return - async with self._aiohttp_session.get(self._settings.base_url + "/studio_speakers") as r: + async with self._aiohttp_session.get(self._base_url + "/studio_speakers") as r: if r.status != 200: text = await r.text() await self.push_error( @@ -184,7 +202,7 @@ class XTTSService(TTSService): embeddings = self._studio_speakers[self._settings.voice] - url = self._settings.base_url + "/tts_stream" + url = self._base_url + "/tts_stream" payload = { "text": text.replace(".", "").replace("*", ""), diff --git a/tests/test_service_init.py b/tests/test_service_init.py new file mode 100644 index 000000000..67dcbb324 --- /dev/null +++ b/tests/test_service_init.py @@ -0,0 +1,181 @@ +# +# Copyright (c) 2024-2026, Daily +# +# SPDX-License-Identifier: BSD 2-Clause License +# + +"""Tests for service settings and initialization patterns. + +Settings objects operate in two modes: + +- **Store mode** (``self._settings``): the live state inside a service. + Every field must hold a real value (``None`` is fine, ``NOT_GIVEN`` is not). +- **Delta mode** (``FooSettings()`` with no args): a sparse update. + Every field must default to ``NOT_GIVEN`` so ``apply_update()`` skips + untouched fields and doesn't accidentally overwrite the store. + +These tests verify both sides of that contract automatically: + +1. **Delta defaults** — Instantiate every ``ServiceSettings`` subclass with + no arguments and assert that every field is ``NOT_GIVEN``. Catches the + bug where a field defaults to ``None`` instead of ``NOT_GIVEN``, which + would cause partial deltas to silently overwrite unrelated store values. + +2. **Store completeness** — Instantiate every concrete service with dummy + args and assert that ``_settings`` contains no ``NOT_GIVEN`` values. + This is the same check that ``validate_complete()`` runs in ``start()``, + but caught here at unit-test time without needing a running pipeline. + Catches services that forget to initialize a field in ``default_settings``. + +All Settings and Service classes are auto-discovered via ``pkgutil``; +new services are covered automatically with no per-service maintenance. +""" + +import importlib +import inspect +import pkgutil +import warnings +from dataclasses import fields + +import pytest + +import pipecat.services +from pipecat.services.ai_service import AIService +from pipecat.services.settings import ServiceSettings, is_given + +# Modules that define abstract base service classes (not concrete services). +_BASE_MODULES = frozenset( + { + "pipecat.services.ai_service", + "pipecat.services.llm_service", + "pipecat.services.stt_service", + "pipecat.services.tts_service", + "pipecat.services.image_gen_service", + "pipecat.services.vision_service", + } +) + + +# --------------------------------------------------------------------------- +# Auto-discovery +# --------------------------------------------------------------------------- + + +def _all_subclasses(cls): + result = set() + for sub in cls.__subclasses__(): + result.add(sub) + result.update(_all_subclasses(sub)) + return result + + +def _import_all_service_modules(): + """Import every module under pipecat.services (skipping missing deps).""" + package = pipecat.services + for _importer, modname, _ispkg in pkgutil.walk_packages( + package.__path__, prefix=package.__name__ + ".", onerror=lambda _name: None + ): + try: + importlib.import_module(modname) + except Exception: + continue + + +_import_all_service_modules() + +ALL_SETTINGS_CLASSES = sorted(_all_subclasses(ServiceSettings), key=lambda c: c.__qualname__) +assert ALL_SETTINGS_CLASSES, "No settings classes discovered" + + +# --------------------------------------------------------------------------- +# Service instantiation helpers +# --------------------------------------------------------------------------- + + +def _try_instantiate(cls): + """Try to instantiate a service with dummy values for required args. + + Inspects the __init__ signature and passes "test" for every required + keyword-only parameter. Services that need non-string required args + or fail for other reasons will raise and be skipped by the test. + """ + sig = inspect.signature(cls.__init__) + kwargs = {} + for name, param in sig.parameters.items(): + if name == "self": + continue + if param.kind in (param.VAR_POSITIONAL, param.VAR_KEYWORD): + continue + if param.default is not param.empty: + continue + # Required parameter — pass a dummy string + kwargs[name] = "test" + return cls(**kwargs) + + +def _discover_service_classes(): + """Return concrete service classes that can be instantiated with dummy args.""" + result = [] + for cls in sorted(_all_subclasses(AIService), key=lambda c: c.__qualname__): + # Skip abstract base classes defined in framework modules. + if cls.__module__ in _BASE_MODULES: + continue + try: + svc = _try_instantiate(cls) + except Exception: + continue + if hasattr(svc, "_settings"): + result.append(cls) + return result + + +ALL_SERVICE_CLASSES = _discover_service_classes() +assert ALL_SERVICE_CLASSES, "No service classes could be instantiated" + + +# --------------------------------------------------------------------------- +# 1. Settings defaults: delta-mode safety +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("settings_cls", ALL_SETTINGS_CLASSES, ids=lambda c: c.__qualname__) +def test_delta_defaults_are_not_given(settings_cls): + """Every field must default to NOT_GIVEN so empty deltas are no-ops. + + A field that defaults to None instead of NOT_GIVEN will cause + apply_update() to overwrite the corresponding store value whenever + a partial delta is applied. + """ + instance = settings_cls() + for f in fields(instance): + if f.name == "extra": + continue + val = getattr(instance, f.name) + assert not is_given(val), ( + f"{settings_cls.__qualname__}.{f.name} defaults to {val!r}, expected NOT_GIVEN" + ) + + +# --------------------------------------------------------------------------- +# 2. Service construction: store-mode completeness +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("service_cls", ALL_SERVICE_CLASSES, ids=lambda c: c.__qualname__) +def test_service_settings_complete(service_cls): + """After construction, _settings must have no NOT_GIVEN values. + + This is what validate_complete() checks in start(). Catching it + here means we don't need a running pipeline to find missing defaults. + """ + try: + svc = _try_instantiate(service_cls) + except Exception: + pytest.skip("Cannot re-instantiate (environment issue)") + for f in fields(svc._settings): + if f.name == "extra": + continue + val = getattr(svc._settings, f.name) + assert is_given(val), ( + f"{service_cls.__qualname__}._settings.{f.name} is NOT_GIVEN after construction" + ) diff --git a/tests/test_settings.py b/tests/test_settings.py index ce3e35af0..201e85745 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -328,8 +328,6 @@ class TestDeepgramSTTSettingsApplyUpdate: defaults = dict( model="nova-3-general", language="en", - encoding="linear16", - channels=1, interim_results=True, smart_format=False, punctuate=True, @@ -350,8 +348,8 @@ class TestDeepgramSTTSettingsApplyUpdate: assert current.punctuate is False assert "punctuate" in changed # Other fields are untouched - assert current.encoding == "linear16" - assert current.channels == 1 + assert current.model == "nova-3-general" + assert current.language == "en" def test_apply_update_model(self): """model field is updated directly.""" @@ -427,8 +425,6 @@ class TestDeepgramSTTSettingsFromMapping: current = DeepgramSTTSettings( model="nova-3-general", language="en", - encoding="linear16", - channels=1, interim_results=True, punctuate=True, profanity_filter=True, @@ -442,7 +438,6 @@ class TestDeepgramSTTSettingsFromMapping: assert current.punctuate is False assert current.diarize is True # Unchanged fields stay put - assert current.encoding == "linear16" assert current.model == "nova-3-general" assert "punctuate" in changed @@ -451,8 +446,6 @@ class TestDeepgramSTTSettingsFromMapping: current = DeepgramSTTSettings( model="nova-3-general", language="en", - encoding="linear16", - channels=1, ) raw = {"model": "nova-2"} @@ -474,16 +467,13 @@ class TestDeepgramSageMakerSTTSettings: store = DeepgramSageMakerSTTSettings( model="nova-3", language="en", - encoding="linear16", - channels=1, - punctuate=True, ) - delta = DeepgramSageMakerSTTSettings(punctuate=False) + delta = DeepgramSageMakerSTTSettings(model="nova-2") changed = store.apply_update(delta) - assert store.punctuate is False - assert store.encoding == "linear16" - assert "punctuate" in changed + assert store.model == "nova-2" + assert store.language == "en" + assert "model" in changed # --------------------------------------------------------------------------- @@ -499,17 +489,17 @@ class TestDeepgramSTTSettingsExtraSync: return DeepgramSTTService(api_key="test-key", sample_rate=16000, **kwargs) def test_extra_synced_to_declared_field_at_init(self): - """If LiveOptions has unknown params in _extra, they can be synced if they match fields.""" + """LiveOptions params that match declared fields are synced at init.""" from pipecat.services.deepgram.stt import LiveOptions - # Use **kwargs to pass undeclared params - live_options = LiveOptions(numerals=True) # 'numerals' goes into _extra + live_options = LiveOptions(numerals=True) svc = self._make_service(live_options=live_options) - # 'numerals' doesn't match a declared DeepgramSTTSettings field, - # so it should stay in extra - assert svc._settings.extra["numerals"] is True + # 'numerals' is a declared DeepgramSTTSettings field, + # so it should be promoted from extra to the declared field + assert svc._settings.numerals is True + assert "numerals" not in svc._settings.extra def test_declared_field_from_live_options(self): """LiveOptions fields that match DeepgramSTTSettings fields are applied.""" @@ -532,7 +522,7 @@ class TestDeepgramSTTSettingsExtraSync: raw_dict = { "diarize": True, # matches declared field "punctuate": False, # matches declared field - "numerals": True, # doesn't match - stays in extra + "custom_param": "value", # doesn't match - stays in extra } delta = DeepgramSTTSettings.from_mapping(raw_dict) @@ -541,7 +531,7 @@ class TestDeepgramSTTSettingsExtraSync: assert delta.diarize is True assert delta.punctuate is False # Unknown stays in extra - assert delta.extra["numerals"] is True + assert delta.extra["custom_param"] == "value" # Now simulate syncing (though from_mapping already routes correctly) delta._sync_extra_to_fields() @@ -549,7 +539,7 @@ class TestDeepgramSTTSettingsExtraSync: # Still the same - from_mapping already put them in the right place assert delta.diarize is True assert delta.punctuate is False - assert delta.extra["numerals"] is True + assert delta.extra["custom_param"] == "value" def test_sync_promotes_extra_to_field_when_not_given(self): """_sync_extra_to_fields promotes extra dict entries to declared fields.""" @@ -611,16 +601,17 @@ class TestDeepgramSTTSettingsExtraSync: """Unknown params (not matching fields) stay in extra and get forwarded.""" from pipecat.services.deepgram.stt import LiveOptions - # numerals isn't a declared field in DeepgramSTTSettings + # 'numerals' is now a declared field; 'custom_param' is not live_options = LiveOptions(numerals=True, custom_param="test") svc = self._make_service(live_options=live_options) - # Should be in extra - assert svc._settings.extra["numerals"] is True + # 'numerals' is a declared field, so it should be promoted + assert svc._settings.numerals is True + # 'custom_param' is unknown, so it stays in extra assert svc._settings.extra["custom_param"] == "test" - # And forwarded to kwargs + # Both forwarded to kwargs kwargs = svc._build_connect_kwargs() assert kwargs["numerals"] == "true" assert kwargs["custom_param"] == "test"