diff --git a/src/pipecat/services/anthropic/llm.py b/src/pipecat/services/anthropic/llm.py index 67777e049..c0c4ca664 100644 --- a/src/pipecat/services/anthropic/llm.py +++ b/src/pipecat/services/anthropic/llm.py @@ -249,43 +249,57 @@ class AnthropicLLMService(LLMService): system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - if model is not None: - _warn_deprecated_param("model", "AnthropicLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "AnthropicLLMSettings") - - _params = params or AnthropicLLMService.InputParams() - - # Handle existing enable_prompt_caching_beta deprecation - 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 - + # 1. Initialize default_settings with hardcoded defaults default_settings = AnthropicLLMSettings( - model=model or "claude-sonnet-4-6", - max_tokens=_params.max_tokens, - enable_prompt_caching=enable_prompt_caching or False, - temperature=_params.temperature, - top_k=_params.top_k, - top_p=_params.top_p, + model="claude-sonnet-4-6", + 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=_params.thinking, - extra=_params.extra if isinstance(_params.extra, dict) else {}, + 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) diff --git a/src/pipecat/services/assemblyai/stt.py b/src/pipecat/services/assemblyai/stt.py index 85d4029b7..e140f7543 100644 --- a/src/pipecat/services/assemblyai/stt.py +++ b/src/pipecat/services/assemblyai/stt.py @@ -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 @@ -108,9 +108,9 @@ 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(), + connection_params: Optional[AssemblyAIConnectionParams] = None, vad_force_turn_endpoint: bool = True, should_interrupt: bool = True, speaker_format: Optional[str] = None, @@ -151,20 +151,23 @@ class AssemblyAISTTService(WebsocketSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. """ + # Resolve connection_params early — needed for validation and turn mode config + _connection_params = connection_params or AssemblyAIConnectionParams() + # 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" + is_u3_pro = _connection_params.speech_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"vad_force_turn_endpoint=True for {_connection_params.speech_model}, " f"or use speech_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 _connection_params.prompt is not None and _connection_params.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 " @@ -174,7 +177,7 @@ class AssemblyAISTTService(WebsocketSTTService): ) # Warn if user sets a custom prompt (recommend testing without one first) - if connection_params.prompt is not None: + if _connection_params.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 " @@ -186,18 +189,32 @@ class AssemblyAISTTService(WebsocketSTTService): # When vad_force_turn_endpoint is enabled, configure connection params # for Pipecat turn detection mode (fast finals for smart turn analyzer) if vad_force_turn_endpoint: - connection_params = self._configure_pipecat_turn_mode(connection_params, is_u3_pro) + _connection_params = self._configure_pipecat_turn_mode(_connection_params, is_u3_pro) + # 1. Initialize default_settings with hardcoded defaults default_settings = AssemblyAISTTSettings( model=None, - language=language, - connection_params=connection_params, + language=Language.EN, + connection_params=AssemblyAIConnectionParams(), ) + + # 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 — only if settings not provided + if connection_params is not None: + _warn_deprecated_param("connection_params", AssemblyAISTTSettings) + if not settings: + default_settings.connection_params = _connection_params + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) super().__init__( - sample_rate=connection_params.sample_rate, + sample_rate=_connection_params.sample_rate, ttfs_p99_latency=ttfs_p99_latency, settings=default_settings, **kwargs, diff --git a/src/pipecat/services/asyncai/tts.py b/src/pipecat/services/asyncai/tts.py index b7ddec2e1..ef5c95bfe 100644 --- a/src/pipecat/services/asyncai/tts.py +++ b/src/pipecat/services/asyncai/tts.py @@ -10,7 +10,7 @@ import asyncio import base64 import json from dataclasses import dataclass, field -from typing import Any, AsyncGenerator, Mapping, Optional +from typing import Any, AsyncGenerator, Mapping, Optional, Self import aiohttp from loguru import logger @@ -88,7 +88,7 @@ class AsyncAITTSSettings(TTSSettings): output_sample_rate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "AsyncAITTSSettings": + def from_mapping(cls, settings: Mapping[str, Any]) -> Self: """Construct settings from a plain dict, destructuring legacy nested ``output_format``.""" flat = dict(settings) nested = flat.pop("output_format", None) @@ -171,25 +171,33 @@ class AsyncAITTSService(AudioContextTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to the parent service. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "AsyncAITTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "AsyncAITTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "AsyncAITTSSettings") - - _params = params or AsyncAITTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = AsyncAITTSSettings( - model=model or "async_flash_v1.0", - voice=voice_id, + model="async_flash_v1.0", + voice=None, + language=None, output_container=container, output_encoding=encoding, output_sample_rate=0, - language=self.language_to_service_language(_params.language) - if _params.language - else 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) @@ -554,25 +562,33 @@ class AsyncAIHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "AsyncAITTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "AsyncAITTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "AsyncAITTSSettings") - - _params = params or AsyncAIHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = AsyncAITTSSettings( - model=model or "async_flash_v1.0", - voice=voice_id, + model="async_flash_v1.0", + voice=None, + language=None, output_container=container, output_encoding=encoding, output_sample_rate=0, - language=self.language_to_service_language(_params.language) - if _params.language - else 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) diff --git a/src/pipecat/services/aws/llm.py b/src/pipecat/services/aws/llm.py index e244a78ac..205d02f1f 100644 --- a/src/pipecat/services/aws/llm.py +++ b/src/pipecat/services/aws/llm.py @@ -816,37 +816,53 @@ class AWSBedrockLLMService(LLMService): system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - if model is not None: - _warn_deprecated_param("model", "AWSBedrockLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "AWSBedrockLLMSettings") - - _params = params or AWSBedrockLLMService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = AWSBedrockLLMSettings( - model=model or "us.amazon.nova-lite-v1:0", - max_tokens=_params.max_tokens, - temperature=_params.temperature, - top_p=_params.top_p, + model="us.amazon.nova-lite-v1:0", + 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, - latency=_params.latency, - additional_model_request_fields=_params.additional_model_request_fields - if isinstance(_params.additional_model_request_fields, dict) - else {}, + 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 + + # 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 + 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) - self._stop_sequences = ( - stop_sequences if stop_sequences is not None else (_params.stop_sequences or []) - ) + # Handle stop_sequences (not a settings field) + if stop_sequences is not None: + self._stop_sequences = stop_sequences + elif params is not None: + self._stop_sequences = params.stop_sequences or [] + else: + self._stop_sequences = [] # Initialize the AWS Bedrock client if not client_config: diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index 887c3f46c..7fec1c73c 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -270,30 +270,40 @@ class AWSNovaSonicLLMService(LLMService): **kwargs: Additional arguments passed to the parent LLMService. """ - # Check for deprecated parameter usage - if model != "amazon.nova-2-sonic-v1:0": - _warn_deprecated_param("model", "AWSNovaSonicLLMSettings", "model") - if voice_id != "matthew": - _warn_deprecated_param("voice_id", "AWSNovaSonicLLMSettings", "voice_id") - if params is not None: - _warn_deprecated_param("params", "AWSNovaSonicLLMSettings") - - _params = params or Params() - + # 1. Initialize default_settings with hardcoded defaults default_settings = AWSNovaSonicLLMSettings( - model=model, - voice_id=voice_id, - temperature=_params.temperature, - max_tokens=_params.max_tokens, - top_p=_params.top_p, + model="amazon.nova-2-sonic-v1:0", + voice_id="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=_params.endpointing_sensitivity, + 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_id") + default_settings.voice_id = voice_id + + # 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) @@ -308,12 +318,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 + _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._system_instruction = system_instruction self._tools = tools diff --git a/src/pipecat/services/aws/stt.py b/src/pipecat/services/aws/stt.py index 061b17889..950624fbf 100644 --- a/src/pipecat/services/aws/stt.py +++ b/src/pipecat/services/aws/stt.py @@ -110,22 +110,27 @@ class AWSTranscribeSTTService(WebsocketSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. """ - if sample_rate is not None: - _warn_deprecated_param("sample_rate", "AWSTranscribeSTTSettings", "sample_rate") - if language is not None: - _warn_deprecated_param("language", "AWSTranscribeSTTSettings", "language") - - _sample_rate = sample_rate or 16000 - _language = language or Language.EN - + # 1. Initialize default_settings with hardcoded defaults default_settings = AWSTranscribeSTTSettings( - language=self.language_to_service_language(_language) or "en-US", - sample_rate=_sample_rate, + language=self.language_to_service_language(Language.EN) or "en-US", + sample_rate=16000, media_encoding="linear16", number_of_channels=1, show_speaker_label=False, enable_channel_identification=False, ) + + # 2. Apply direct init arg overrides (deprecated) + if sample_rate is not None: + _warn_deprecated_param("sample_rate", AWSTranscribeSTTSettings, "sample_rate") + default_settings.sample_rate = sample_rate + 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) @@ -136,9 +141,9 @@ class AWSTranscribeSTTService(WebsocketSTTService): ) # Validate sample rate - AWS Transcribe only supports 8000 Hz or 16000 Hz - if _sample_rate not in [8000, 16000]: + if default_settings.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." + f"AWS Transcribe only supports 8000 Hz or 16000 Hz sample rates. Converting from {default_settings.sample_rate} Hz to 16000 Hz." ) self._settings.sample_rate = 16000 diff --git a/src/pipecat/services/aws/tts.py b/src/pipecat/services/aws/tts.py index 83ef4125c..f248db27a 100644 --- a/src/pipecat/services/aws/tts.py +++ b/src/pipecat/services/aws/tts.py @@ -209,25 +209,39 @@ class AWSPollyTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "AWSPollyTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "AWSPollyTTSSettings") - - _params = params or AWSPollyTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = AWSPollyTTSSettings( model=None, - voice=voice_id or "Joanna", - 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, + 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) diff --git a/src/pipecat/services/azure/image.py b/src/pipecat/services/azure/image.py index 9f5d48c33..ca58644f2 100644 --- a/src/pipecat/services/azure/image.py +++ b/src/pipecat/services/azure/image.py @@ -68,7 +68,7 @@ class AzureImageGenServiceREST(ImageGenService): parameters, ``settings`` values take precedence. """ if model is not None: - _warn_deprecated_param("model", "AzureImageGenSettings", "model") + _warn_deprecated_param("model", AzureImageGenSettings, "model") default_settings = AzureImageGenSettings(model=model) if settings is not None: diff --git a/src/pipecat/services/azure/llm.py b/src/pipecat/services/azure/llm.py index 3c28e190e..734a0bacf 100644 --- a/src/pipecat/services/azure/llm.py +++ b/src/pipecat/services/azure/llm.py @@ -48,10 +48,15 @@ class AzureLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="gpt-4o") - default_settings = OpenAILLMSettings(model=model or "gpt-4o") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/azure/stt.py b/src/pipecat/services/azure/stt.py index 02a7ca8ed..66f871ad3 100644 --- a/src/pipecat/services/azure/stt.py +++ b/src/pipecat/services/azure/stt.py @@ -107,15 +107,22 @@ class AzureSTTService(STTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService. """ - if language != Language.EN_US: - _warn_deprecated_param("language", "AzureSTTSettings", "language") - + # 1. Initialize default_settings with hardcoded defaults default_settings = AzureSTTSettings( model=None, region=region, - language=language_to_azure_language(language) if language else None, + language=language_to_azure_language(Language.EN_US), sample_rate=sample_rate, ) + + # 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) diff --git a/src/pipecat/services/azure/tts.py b/src/pipecat/services/azure/tts.py index 7e5791f03..3a67cb2ff 100644 --- a/src/pipecat/services/azure/tts.py +++ b/src/pipecat/services/azure/tts.py @@ -290,27 +290,43 @@ class AzureTTSService(TTSService, AzureBaseTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent WordTTSService. """ - if voice is not None: - _warn_deprecated_param("voice", "AzureTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "AzureTTSSettings") - - _params = params or AzureBaseTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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 or "en-US-SaraNeural", - volume=_params.volume, + 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) @@ -779,27 +795,43 @@ class AzureHttpTTSService(TTSService, AzureBaseTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice is not None: - _warn_deprecated_param("voice", "AzureTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "AzureTTSSettings") - - _params = params or AzureBaseTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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 or "en-US-SaraNeural", - volume=_params.volume, + 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) diff --git a/src/pipecat/services/camb/tts.py b/src/pipecat/services/camb/tts.py index de8b16ab8..9a1b753a6 100644 --- a/src/pipecat/services/camb/tts.py +++ b/src/pipecat/services/camb/tts.py @@ -230,34 +230,45 @@ class CambTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "CambTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "CambTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "CambTTSSettings") + # 1. Initialize default_settings with hardcoded defaults + default_settings = CambTTSSettings( + model="mars-flash", + voice=147320, + language="en-us", + user_instructions=None, + ) - _params = params or CambTTSService.InputParams() - _model = model or "mars-flash" + # 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 + _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"sample rate. Current rate of {sample_rate}Hz may cause issues." ) - default_settings = CambTTSSettings( - model=_model, - voice=voice_id or 147320, - language=( - self.language_to_service_language(_params.language) if _params.language else "en-us" - ), - user_instructions=_params.user_instructions, - ) - if settings is not None: - default_settings.apply_update(settings) - super().__init__( sample_rate=sample_rate, settings=default_settings, diff --git a/src/pipecat/services/cartesia/stt.py b/src/pipecat/services/cartesia/stt.py index 530f6a4d1..aa66b102e 100644 --- a/src/pipecat/services/cartesia/stt.py +++ b/src/pipecat/services/cartesia/stt.py @@ -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 NOT_GIVEN, STTSettings, _NotGiven, _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 @@ -177,26 +177,34 @@ class CartesiaSTTService(WebsocketSTTService): """ 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. (no deprecated direct args for this service) - default_settings = CartesiaSTTSettings( - model=merged_options["model"], - language=merged_options.get("language"), - encoding=merged_options.get("encoding", "pcm_s16le"), - ) + # 3. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", CartesiaSTTSettings) + if not settings: + lo_dict = live_options.to_dict() + # Filter out "None" string values + lo_dict = { + k: v + for k, v in lo_dict.items() + if (not isinstance(v, str) or v != "None") and k != "sample_rate" + } + if "model" in lo_dict: + default_settings.model = lo_dict["model"] + if "language" in lo_dict: + default_settings.language = lo_dict["language"] + if "encoding" in lo_dict: + default_settings.encoding = lo_dict["encoding"] + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/cartesia/tts.py b/src/pipecat/services/cartesia/tts.py index 82f3b7d73..6930026f3 100644 --- a/src/pipecat/services/cartesia/tts.py +++ b/src/pipecat/services/cartesia/tts.py @@ -11,7 +11,7 @@ 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 Any, AsyncGenerator, List, Literal, Mapping, Optional, Self from loguru import logger from pydantic import BaseModel, Field @@ -216,7 +216,7 @@ class CartesiaTTSSettings(TTSSettings): pronunciation_dict_id: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN) @classmethod - def from_mapping(cls, settings: Mapping[str, Any]) -> "CartesiaTTSSettings": + def from_mapping(cls, settings: Mapping[str, Any]) -> Self: """Construct settings from a plain dict, destructuring legacy nested ``output_format``.""" flat = dict(settings) nested = flat.pop("output_format", None) @@ -316,13 +316,6 @@ class CartesiaTTSService(AudioContextTTSService): **kwargs: Additional arguments passed to the parent service. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "CartesiaTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "CartesiaTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "CartesiaTTSSettings") - # By default, we aggregate sentences before sending to TTS. This adds # ~200-300ms of latency per sentence (waiting for the sentence-ending # punctuation token from the LLM). Setting @@ -336,22 +329,39 @@ 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=model or "sonic-3", - voice=voice_id, + model="sonic-3", 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, ) + + # 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.speed is not None: + default_settings.speed = params.speed + if params.emotion is not None: + default_settings.emotion = params.emotion + 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) @@ -782,29 +792,38 @@ class CartesiaHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "CartesiaTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "CartesiaTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "CartesiaTTSSettings") - - _params = params or CartesiaHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = CartesiaTTSSettings( - model=model or "sonic-3", - voice=voice_id, + model="sonic-3", 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, ) + + # 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.speed is not None: + default_settings.speed = params.speed + if params.emotion is not None: + default_settings.emotion = params.emotion + 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) diff --git a/src/pipecat/services/cerebras/llm.py b/src/pipecat/services/cerebras/llm.py index 053594083..98fbfe0e3 100644 --- a/src/pipecat/services/cerebras/llm.py +++ b/src/pipecat/services/cerebras/llm.py @@ -46,10 +46,15 @@ class CerebrasLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="gpt-oss-120b") - default_settings = OpenAILLMSettings(model=model or "gpt-oss-120b") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/deepgram/flux/stt.py b/src/pipecat/services/deepgram/flux/stt.py index 04c2f1da3..8ddd2ef0d 100644 --- a/src/pipecat/services/deepgram/flux/stt.py +++ b/src/pipecat/services/deepgram/flux/stt.py @@ -206,10 +206,6 @@ class DeepgramFluxSTTService(WebsocketSTTService): ), ) """ - if model is not None: - _warn_deprecated_param("model", "DeepgramFluxSTTSettings", "model") - if params is not None: - _warn_deprecated_param("params", "DeepgramFluxSTTSettings") # Note: For DeepgramFluxSTTService, differently from other processes, we need to create # the _receive_task inside _connect_websocket, because the websocket should only be # considered connected and ready to send audio once we receive from Flux the message @@ -220,20 +216,39 @@ 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=model or "flux-general-en", + model="flux-general-en", 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, + eager_eot_threshold=None, + eot_threshold=None, + eot_timeout_ms=None, + keyterm=[], + mip_opt_out=None, + 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.mip_opt_out = params.mip_opt_out + default_settings.tag = params.tag or [] + default_settings.min_confidence = params.min_confidence + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/deepgram/sagemaker/stt.py b/src/pipecat/services/deepgram/sagemaker/stt.py index 6d813157d..d7a867e38 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, field from typing import Any, AsyncGenerator, Optional from loguru import logger @@ -32,8 +32,7 @@ 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.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import DEEPGRAM_SAGEMAKER_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language @@ -51,13 +50,14 @@ except ModuleNotFoundError as e: @dataclass -class DeepgramSageMakerSTTSettings(_DeepgramSTTSettingsBase): +class DeepgramSageMakerSTTSettings(STTSettings): """Settings for the Deepgram SageMaker STT service. - See ``_DeepgramSTTSettingsBase`` for full documentation. + Parameters: + live_options: Deepgram LiveOptions for the SageMaker connection. """ - pass + live_options: Any | _NotGiven = field(default_factory=lambda: NOT_GIVEN) class DeepgramSageMakerSTTService(STTService): @@ -130,13 +130,29 @@ class DeepgramSageMakerSTTService(STTService): punctuate=True, ) + # 1. Initialize default_settings with hardcoded defaults default_settings = DeepgramSageMakerSTTSettings( - model=default_options.model, - language=default_options.language, + model="nova-3", + language=Language.EN, live_options=default_options, ) - if live_options: - default_settings._merge_live_options_delta(live_options) + + # 2. (no deprecated direct args like model= for this service) + + # 3. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", DeepgramSageMakerSTTSettings) + if not settings: + # Merge user live_options onto defaults + merged_dict = {**default_options.to_dict(), **live_options.to_dict()} + merged_live_options = LiveOptions(**merged_dict) + default_settings.live_options = merged_live_options + if hasattr(live_options, "model") and live_options.model is not None: + default_settings.model = live_options.model + if hasattr(live_options, "language") and live_options.language is not None: + default_settings.language = live_options.language + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/deepgram/sagemaker/tts.py b/src/pipecat/services/deepgram/sagemaker/tts.py index 8d03f6eac..62cd25188 100644 --- a/src/pipecat/services/deepgram/sagemaker/tts.py +++ b/src/pipecat/services/deepgram/sagemaker/tts.py @@ -102,7 +102,7 @@ class DeepgramSageMakerTTSService(TTSService): **kwargs: Additional arguments passed to the parent TTSService. """ if voice is not None: - _warn_deprecated_param("voice", "DeepgramSageMakerTTSSettings", "voice") + _warn_deprecated_param("voice", DeepgramSageMakerTTSSettings, "voice") voice = voice or "aura-2-helena-en" diff --git a/src/pipecat/services/deepgram/stt.py b/src/pipecat/services/deepgram/stt.py index fe3add7cf..f311567aa 100644 --- a/src/pipecat/services/deepgram/stt.py +++ b/src/pipecat/services/deepgram/stt.py @@ -25,7 +25,14 @@ 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 ( + _S, + 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 @@ -303,6 +310,7 @@ class DeepgramSTTService(STTService): ) base_url = url + # 1. Initialize default_settings with hardcoded defaults default_settings = DeepgramSTTSettings( model="nova-3-general", language=Language.EN, @@ -317,13 +325,19 @@ class DeepgramSTTService(STTService): endpointing=None, ) - 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"} - ) - default_settings.apply_update(delta) + # 2. (no deprecated direct args like model= for this service) + # 3. Apply live_options overrides — only if settings not provided + if live_options is not None: + _warn_deprecated_param("live_options", DeepgramSTTSettings) + if not settings: + lo_dict = live_options.to_dict() + delta = DeepgramSTTSettings.from_mapping( + {k: v for k, v in lo_dict.items() if k != "sample_rate"} + ) + default_settings.apply_update(delta) + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/deepgram/tts.py b/src/pipecat/services/deepgram/tts.py index 7c391490d..98a615f9b 100644 --- a/src/pipecat/services/deepgram/tts.py +++ b/src/pipecat/services/deepgram/tts.py @@ -98,20 +98,26 @@ class DeepgramTTSService(WebsocketTTSService): Raises: ValueError: If encoding is not in SUPPORTED_ENCODINGS. """ - if voice is not None: - _warn_deprecated_param("voice", "DeepgramTTSSettings", "voice") - if encoding.lower() not in self.SUPPORTED_ENCODINGS: raise ValueError( 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=voice or "aura-2-helena-en", - voice=voice or "aura-2-helena-en", + model="aura-2-helena-en", + voice="aura-2-helena-en", language=None, encoding=encoding, ) + + # 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) @@ -414,15 +420,21 @@ class DeepgramHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ - if voice is not None: - _warn_deprecated_param("voice", "DeepgramTTSSettings", "voice") - + # 1. Initialize default_settings with hardcoded defaults default_settings = DeepgramTTSSettings( - model=voice or "aura-2-helena-en", - voice=voice or "aura-2-helena-en", + model="aura-2-helena-en", + voice="aura-2-helena-en", language=None, encoding=encoding, ) + + # 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) diff --git a/src/pipecat/services/deepseek/llm.py b/src/pipecat/services/deepseek/llm.py index 8cc9ac56e..c383f5609 100644 --- a/src/pipecat/services/deepseek/llm.py +++ b/src/pipecat/services/deepseek/llm.py @@ -46,10 +46,15 @@ class DeepSeekLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="deepseek-chat") - default_settings = OpenAILLMSettings(model=model or "deepseek-chat") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/elevenlabs/stt.py b/src/pipecat/services/elevenlabs/stt.py index 1eebcffde..d93f95332 100644 --- a/src/pipecat/services/elevenlabs/stt.py +++ b/src/pipecat/services/elevenlabs/stt.py @@ -275,20 +275,29 @@ class ElevenLabsSTTService(SegmentedSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - if model is not None: - _warn_deprecated_param("model", "ElevenLabsSTTSettings", "model") - if params is not None: - _warn_deprecated_param("params", "ElevenLabsSTTSettings") - - _params = params or ElevenLabsSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = ElevenLabsSTTSettings( - model=model or "scribe_v2", - language=self.language_to_service_language(_params.language) - if _params.language - else "eng", - tag_audio_events=_params.tag_audio_events, + 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) @@ -515,25 +524,40 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to WebsocketSTTService. """ - if model is not None: - _warn_deprecated_param("model", "ElevenLabsRealtimeSTTSettings", "model") - if params is not None: - _warn_deprecated_param("params", "ElevenLabsRealtimeSTTSettings") - - _params = params or ElevenLabsRealtimeSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = ElevenLabsRealtimeSTTSettings( - model=model or "scribe_v2_realtime", - 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, + model="scribe_v2_realtime", + language=None, + commit_strategy=CommitStrategy.MANUAL, + 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 + default_settings.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) diff --git a/src/pipecat/services/elevenlabs/tts.py b/src/pipecat/services/elevenlabs/tts.py index 15c2dbb2e..3cec12431 100644 --- a/src/pipecat/services/elevenlabs/tts.py +++ b/src/pipecat/services/elevenlabs/tts.py @@ -408,13 +408,6 @@ class ElevenLabsTTSService(AudioContextTTSService): **kwargs: Additional arguments passed to the parent service. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "ElevenLabsTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "ElevenLabsTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "ElevenLabsTTSSettings") - # By default, we aggregate sentences before sending to TTS. This adds # ~200-300ms of latency per sentence (waiting for the sentence-ending # punctuation token from the LLM). Setting @@ -431,24 +424,49 @@ 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=model or "eleven_turbo_v2_5", - 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, + model="eleven_turbo_v2_5", ) + + # 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: + default_settings.auto_mode = str(params.auto_mode).lower() + if params.enable_ssml_parsing is not None: + default_settings.enable_ssml_parsing = params.enable_ssml_parsing + if params.enable_logging is not None: + default_settings.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) @@ -469,11 +487,7 @@ class ElevenLabsTTSService(AudioContextTTSService): self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = ( - pronunciation_dictionary_locators - if pronunciation_dictionary_locators is not None - else _params.pronunciation_dictionary_locators - ) + self._pronunciation_dictionary_locators = _pronunciation_dictionary_locators self._cumulative_time = 0 # Track partial words that span across alignment chunks @@ -982,29 +996,44 @@ class ElevenLabsHttpTTSService(TTSService): **kwargs: Additional arguments passed to the parent service. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "ElevenLabsHttpTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "ElevenLabsHttpTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "ElevenLabsHttpTTSSettings") - - _params = params or ElevenLabsHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = ElevenLabsHttpTTSSettings( - model=model or "eleven_turbo_v2_5", - 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, + model="eleven_turbo_v2_5", ) + + # 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) @@ -1025,11 +1054,7 @@ class ElevenLabsHttpTTSService(TTSService): self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = ( - pronunciation_dictionary_locators - if pronunciation_dictionary_locators is not None - else _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 d172f77dd..5d061619c 100644 --- a/src/pipecat/services/fal/image.py +++ b/src/pipecat/services/fal/image.py @@ -95,10 +95,15 @@ class FalImageGenService(ImageGenService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent ImageGenService. """ - if model is not None: - _warn_deprecated_param("model", "FalImageGenSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = FalImageGenSettings(model="fal-ai/fast-sdxl") - default_settings = FalImageGenSettings(model=model or "fal-ai/fast-sdxl") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", FalImageGenSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/fal/stt.py b/src/pipecat/services/fal/stt.py index 1a8a7076c..b5561d964 100644 --- a/src/pipecat/services/fal/stt.py +++ b/src/pipecat/services/fal/stt.py @@ -217,20 +217,29 @@ class FalSTTService(SegmentedSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - if params is not None: - _warn_deprecated_param("params", "FalSTTSettings") - - _params = params or FalSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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, + language=language_to_fal_language(Language.EN) or "en", + task="transcribe", + chunk_level="segment", + version="3", ) + + # 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" + ) + default_settings.task = params.task + default_settings.chunk_level = params.chunk_level + default_settings.version = params.version + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/fireworks/llm.py b/src/pipecat/services/fireworks/llm.py index 33d7d22e2..cb5a0cf39 100644 --- a/src/pipecat/services/fireworks/llm.py +++ b/src/pipecat/services/fireworks/llm.py @@ -46,12 +46,15 @@ class FireworksLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="accounts/fireworks/models/firefunction-v2") - default_settings = OpenAILLMSettings( - model=model or "accounts/fireworks/models/firefunction-v2" - ) + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/fish/tts.py b/src/pipecat/services/fish/tts.py index 431b51729..3d4412186 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 @@ -72,7 +72,7 @@ class FishAudioTTSSettings(TTSSettings): _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) @@ -156,15 +156,6 @@ class FishAudioTTSService(InterruptibleTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ - if reference_id is not None: - _warn_deprecated_param("reference_id", "FishAudioTTSSettings", "voice") - if model_id is not None: - _warn_deprecated_param("model_id", "FishAudioTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "FishAudioTTSSettings") - - _params = params or FishAudioTTSService.InputParams() - # Validation for model and reference_id parameters if model and reference_id: raise ValueError( @@ -184,17 +175,42 @@ class FishAudioTTSService(InterruptibleTTSService): ) reference_id = model + # 1. Initialize default_settings with hardcoded defaults default_settings = FishAudioTTSSettings( - model=model_id or "s1", - voice=reference_id, + model="s1", + voice=None, fish_sample_rate=0, - latency=_params.latency, + latency="normal", format=output_format, - normalize=_params.normalize, - prosody_speed=_params.prosody_speed, - prosody_volume=_params.prosody_volume, - reference_id=reference_id, + 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) diff --git a/src/pipecat/services/gladia/stt.py b/src/pipecat/services/gladia/stt.py index e1e0d9276..a12829b0d 100644 --- a/src/pipecat/services/gladia/stt.py +++ b/src/pipecat/services/gladia/stt.py @@ -289,23 +289,6 @@ class GladiaSTTService(WebsocketSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService parent class. """ - if model is not None: - _warn_deprecated_param("model", "GladiaSTTSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GladiaSTTSettings") - - 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") @@ -316,28 +299,64 @@ 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=model or "solaria-1", + model="solaria-1", 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, + encoding="wav/pcm", + bit_depth=16, + channels=1, + custom_metadata=None, + endpointing=None, + maximum_duration_without_endpointing=5, + language_config=None, + 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: + default_settings.encoding = params.encoding + default_settings.bit_depth = params.bit_depth + default_settings.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 + 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 + ) + default_settings.language_config = language_config + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/google/gemini_live/llm.py b/src/pipecat/services/google/gemini_live/llm.py index 518684dfb..6e7a8f8a1 100644 --- a/src/pipecat/services/google/gemini_live/llm.py +++ b/src/pipecat/services/google/gemini_live/llm.py @@ -708,36 +708,63 @@ class GeminiLiveLLMService(LLMService): DeprecationWarning, stacklevel=2, ) - if model is not None: - _warn_deprecated_param("model", "GeminiLiveLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GeminiLiveLLMSettings") - - _params = params or InputParams() + # 1. Initialize default_settings with hardcoded defaults default_settings = GeminiLiveLLMSettings( - model=model or "models/gemini-2.5-flash-native-audio-preview-12-2025", - 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, + model="models/gemini-2.5-flash-native-audio-preview-12-2025", + 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=_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 {}, + 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 + + # 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) @@ -750,7 +777,7 @@ class GeminiLiveLLMService(LLMService): 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 diff --git a/src/pipecat/services/google/gemini_live/llm_vertex.py b/src/pipecat/services/google/gemini_live/llm_vertex.py index eadcb66d1..5d63251d9 100644 --- a/src/pipecat/services/google/gemini_live/llm_vertex.py +++ b/src/pipecat/services/google/gemini_live/llm_vertex.py @@ -20,6 +20,8 @@ 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, @@ -109,11 +111,6 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): "Invalid parameter 'api_key'. Use 'credentials' or 'credentials_path' for Vertex AI authentication." ) - if model is not None: - _warn_deprecated_param("model", "GeminiLiveLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GeminiLiveLLMSettings") - # These need to be set before calling super().__init__() because # super().__init__() invokes create_client(), which needs these. self._credentials = self._get_credentials(credentials, credentials_path) @@ -123,31 +120,63 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): # 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. - _params = params or InputParams() + # 1. Initialize default_settings with hardcoded defaults default_settings = GeminiLiveLLMSettings( - model=model or "google/gemini-live-2.5-flash-native-audio", - 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, + model="google/gemini-live-2.5-flash-native-audio", + 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=_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 {}, + 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 + + # 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) diff --git a/src/pipecat/services/google/image.py b/src/pipecat/services/google/image.py index ce29c0276..09ec61554 100644 --- a/src/pipecat/services/google/image.py +++ b/src/pipecat/services/google/image.py @@ -90,17 +90,21 @@ class GoogleImageGenService(ImageGenService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent ImageGenService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = GoogleImageGenSettings(model="imagen-3.0-generate-002") + + # 3. Apply params overrides — only if settings not provided if params is not None: - _warn_deprecated_param("params", "GoogleImageGenSettings") + _warn_deprecated_param("params", GoogleImageGenSettings) + if not settings: + default_settings.model = params.model - params = params or GoogleImageGenService.InputParams() - - default_settings = GoogleImageGenSettings(model=params.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) - self._params = params + self._params = params or GoogleImageGenService.InputParams() # Add client header http_options = update_google_client_http_options(http_options) diff --git a/src/pipecat/services/google/llm.py b/src/pipecat/services/google/llm.py index 5d5a87188..49e6d2366 100644 --- a/src/pipecat/services/google/llm.py +++ b/src/pipecat/services/google/llm.py @@ -814,27 +814,40 @@ class GoogleLLMService(LLMService): http_options: HTTP options for the client. **kwargs: Additional arguments passed to parent class. """ - if model is not None: - _warn_deprecated_param("model", "GoogleLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GoogleLLMSettings") - - _params = params or GoogleLLMService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = GoogleLLMSettings( - model=model or "gemini-2.5-flash", - max_tokens=_params.max_tokens, - temperature=_params.temperature, - top_k=_params.top_k, - top_p=_params.top_p, + model="gemini-2.5-flash", + 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=_params.thinking, - extra=_params.extra if isinstance(_params.extra, dict) else {}, + 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 + + # 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) diff --git a/src/pipecat/services/google/llm_openai.py b/src/pipecat/services/google/llm_openai.py index aa8794469..4705e8f68 100644 --- a/src/pipecat/services/google/llm_openai.py +++ b/src/pipecat/services/google/llm_openai.py @@ -84,10 +84,15 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): stacklevel=2, ) - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="gemini-2.0-flash") - default_settings = OpenAILLMSettings(model=model or "gemini-2.0-flash") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/google/llm_vertex.py b/src/pipecat/services/google/llm_vertex.py index 9258a4d67..b1a9de584 100644 --- a/src/pipecat/services/google/llm_vertex.py +++ b/src/pipecat/services/google/llm_vertex.py @@ -148,15 +148,9 @@ class GoogleVertexLLMService(GoogleLLMService): "Invalid parameter 'api_key'. Use 'credentials' or 'credentials_path' for Vertex AI authentication." ) - if model is not None: - _warn_deprecated_param("model", "GoogleLLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GoogleLLMSettings") - - # 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: @@ -188,22 +182,40 @@ class GoogleVertexLLMService(GoogleLLMService): self._project_id = project_id self._location = location - # Build default_settings from deprecated args - _params = params or GoogleLLMService.InputParams() + # 1. Initialize default_settings with hardcoded defaults default_settings = GoogleLLMSettings( - model=model or "gemini-2.5-flash", - max_tokens=_params.max_tokens, - temperature=_params.temperature, - top_k=_params.top_k, - top_p=_params.top_p, + model="gemini-2.5-flash", + 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=_params.thinking, - extra=_params.extra if isinstance(_params.extra, dict) else {}, + 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 + + # 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) diff --git a/src/pipecat/services/google/stt.py b/src/pipecat/services/google/stt.py index 23a586b96..5415a5403 100644 --- a/src/pipecat/services/google/stt.py +++ b/src/pipecat/services/google/stt.py @@ -509,26 +509,44 @@ class GoogleSTTService(STTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - if params is not None: - _warn_deprecated_param("params", "GoogleSTTSettings") - - _params = params or GoogleSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = GoogleSTTSettings( language=None, - languages=list(_params.language_list), + languages=[Language.EN_US], 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, + 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) diff --git a/src/pipecat/services/google/tts.py b/src/pipecat/services/google/tts.py index 78719f8fa..6b17caed5 100644 --- a/src/pipecat/services/google/tts.py +++ b/src/pipecat/services/google/tts.py @@ -622,27 +622,40 @@ class GoogleHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "GoogleHttpTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "GoogleHttpTTSSettings") - - _params = params or GoogleHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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 or "en-US-Chirp3-HD-Charon", + 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) @@ -1062,21 +1075,28 @@ class GoogleTTSService(GoogleBaseTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "GoogleStreamTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "GoogleStreamTTSSettings") - - _params = params or GoogleTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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 or "en-US-Chirp3-HD-Charon", + 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) @@ -1292,34 +1312,47 @@ class GeminiTTSService(GoogleBaseTTSService): DeprecationWarning, stacklevel=2, ) - if model is not None: - _warn_deprecated_param("model", "GeminiTTSSettings", "model") - if voice_id is not None: - _warn_deprecated_param("voice_id", "GeminiTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "GeminiTTSSettings") if sample_rate and sample_rate != self.GOOGLE_SAMPLE_RATE: logger.warning( 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() - - voice_id = voice_id or "Kore" - 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=model or "gemini-2.5-flash-tts", - 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, + 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) diff --git a/src/pipecat/services/gradium/stt.py b/src/pipecat/services/gradium/stt.py index 5974133c0..51ac8a7cd 100644 --- a/src/pipecat/services/gradium/stt.py +++ b/src/pipecat/services/gradium/stt.py @@ -148,16 +148,23 @@ class GradiumSTTService(WebsocketSTTService): stacklevel=2, ) - if params is not None: - _warn_deprecated_param("params", "GradiumSTTSettings") - - _params = params or GradiumSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = GradiumSTTSettings( model=None, - language=_params.language, - delay_in_frames=_params.delay_in_frames or None, + language=None, + delay_in_frames=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 + default_settings.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) diff --git a/src/pipecat/services/gradium/tts.py b/src/pipecat/services/gradium/tts.py index 6f076f933..b3b9b50ca 100644 --- a/src/pipecat/services/gradium/tts.py +++ b/src/pipecat/services/gradium/tts.py @@ -103,19 +103,28 @@ class GradiumTTSService(AudioContextTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "GradiumTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "GradiumTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "GradiumTTSSettings") - + # 1. Initialize default_settings with hardcoded defaults default_settings = GradiumTTSSettings( - model=model or "default", - voice=voice_id or "YTpq7expH9539ERJ", + model="default", + voice="YTpq7expH9539ERJ", language=None, output_format="pcm", ) + + # 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) diff --git a/src/pipecat/services/grok/llm.py b/src/pipecat/services/grok/llm.py index 2e6a93c4e..f552f059a 100644 --- a/src/pipecat/services/grok/llm.py +++ b/src/pipecat/services/grok/llm.py @@ -102,10 +102,15 @@ class GrokLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="grok-3-beta") - default_settings = OpenAILLMSettings(model=model or "grok-3-beta") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/grok/realtime/llm.py b/src/pipecat/services/grok/realtime/llm.py index 87f5eaaaa..2f2df1b45 100644 --- a/src/pipecat/services/grok/realtime/llm.py +++ b/src/pipecat/services/grok/realtime/llm.py @@ -153,11 +153,7 @@ class GrokRealtimeLLMService(LLMService): start_audio_paused: Whether to start with audio input paused. Defaults to False. **kwargs: Additional arguments passed to parent LLMService. """ - if session_properties is not None: - _warn_deprecated_param( - "session_properties", "GrokRealtimeLLMSettings", "session_properties" - ) - + # 1. Initialize default_settings with hardcoded defaults default_settings = GrokRealtimeLLMSettings( model=None, temperature=None, @@ -169,8 +165,17 @@ class GrokRealtimeLLMService(LLMService): seed=None, filter_incomplete_user_turns=False, user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), + session_properties=events.SessionProperties(), ) + + # 2. Apply direct init arg overrides (deprecated) + if session_properties is not None: + _warn_deprecated_param( + "session_properties", GrokRealtimeLLMSettings, "session_properties" + ) + default_settings.session_properties = session_properties + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/groq/llm.py b/src/pipecat/services/groq/llm.py index 0ea3b3f50..f88d5a877 100644 --- a/src/pipecat/services/groq/llm.py +++ b/src/pipecat/services/groq/llm.py @@ -45,10 +45,15 @@ class GroqLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="llama-3.3-70b-versatile") - default_settings = OpenAILLMSettings(model=model or "llama-3.3-70b-versatile") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/groq/stt.py b/src/pipecat/services/groq/stt.py index e6ea42fd8..ac6a4325c 100644 --- a/src/pipecat/services/groq/stt.py +++ b/src/pipecat/services/groq/stt.py @@ -69,27 +69,30 @@ class GroqSTTService(BaseWhisperSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ - if model is not None: - _warn_deprecated_param("model", "BaseWhisperSTTSettings", "model") - if language is not None: - _warn_deprecated_param("language", "BaseWhisperSTTSettings", "language") - if prompt is not None: - _warn_deprecated_param("prompt", "BaseWhisperSTTSettings", "prompt") - if temperature is not None: - _warn_deprecated_param("temperature", "BaseWhisperSTTSettings", "temperature") - - model = model or "whisper-large-v3-turbo" - language = language or Language.EN - - # Build settings from deprecated params and pass via settings= - # to avoid double deprecation warnings in BaseWhisperSTTService. + # --- 1. Hardcoded defaults --- default_settings = BaseWhisperSTTSettings( - model=model, - language=self.language_to_service_language(language), + model="whisper-large-v3-turbo", + language=self.language_to_service_language(Language.EN), base_url=base_url, - prompt=prompt, - temperature=temperature, ) + + # --- 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) diff --git a/src/pipecat/services/groq/tts.py b/src/pipecat/services/groq/tts.py index d16964d8c..b1c546713 100644 --- a/src/pipecat/services/groq/tts.py +++ b/src/pipecat/services/groq/tts.py @@ -114,26 +114,35 @@ class GroqTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ - if model_name is not None: - _warn_deprecated_param("model_name", "GroqTTSSettings", "model") - if voice_id is not None: - _warn_deprecated_param("voice_id", "GroqTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "GroqTTSSettings") - 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=model_name or "canopylabs/orpheus-v1-english", - voice=voice_id or "autumn", - language=str(_params.language) if _params.language else "en", + model="canopylabs/orpheus-v1-english", + voice="autumn", + language="en", output_format=output_format, - speed=_params.speed, + speed=1.0, groq_sample_rate=sample_rate, ) + + # 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) diff --git a/src/pipecat/services/hume/tts.py b/src/pipecat/services/hume/tts.py index 5b7300816..7b0ecd0c8 100644 --- a/src/pipecat/services/hume/tts.py +++ b/src/pipecat/services/hume/tts.py @@ -126,11 +126,6 @@ class HumeTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "HumeTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "HumeTTSSettings") - api_key = api_key or os.getenv("HUME_API_KEY") if not api_key: raise ValueError("HumeTTSService requires an API key (env HUME_API_KEY or api_key=)") @@ -140,16 +135,30 @@ 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=voice_id, + voice=None, language=None, # Not applicable here - description=_params.description, - speed=_params.speed, - trailing_silence=_params.trailing_silence, + 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) diff --git a/src/pipecat/services/inworld/tts.py b/src/pipecat/services/inworld/tts.py index f1797ad55..688ba542a 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 @@ -91,7 +102,7 @@ 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) @@ -168,27 +179,42 @@ class InworldHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "InworldTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "InworldTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "InworldTTSSettings") - - _params = params or InworldHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = InworldTTSSettings( - model=model or "inworld-tts-1.5-max", - voice=voice_id or "Ashley", + model="inworld-tts-1.5-max", + voice="Ashley", language=None, audio_encoding=encoding, audio_sample_rate=0, - speaking_rate=_params.speaking_rate, - temperature=_params.temperature, - timestamp_transport_strategy=_params.timestamp_transport_strategy, + 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) @@ -580,27 +606,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. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "InworldTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "InworldTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "InworldTTSSettings") - - _params = params or InworldTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = InworldTTSSettings( - model=model or "inworld-tts-1.5-max", - voice=voice_id or "Ashley", + model="inworld-tts-1.5-max", + voice="Ashley", 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, + 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) @@ -622,8 +671,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 diff --git a/src/pipecat/services/kokoro/tts.py b/src/pipecat/services/kokoro/tts.py index 8bab78f93..7e53060da 100644 --- a/src/pipecat/services/kokoro/tts.py +++ b/src/pipecat/services/kokoro/tts.py @@ -151,19 +151,28 @@ class KokoroTTSService(TTSService): **kwargs: Additional arguments passed to parent `TTSService`. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "KokoroTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "KokoroTTSSettings") - - _params = params or KokoroTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = KokoroTTSSettings( model=None, - voice=voice_id, - language=language_to_kokoro_language(_params.language), - lang_code=language_to_kokoro_language(_params.language), + voice=None, + language=language_to_kokoro_language(Language.EN), + lang_code=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: + lang_code = language_to_kokoro_language(params.language) + default_settings.language = lang_code + default_settings.lang_code = lang_code + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) @@ -172,14 +181,14 @@ class KokoroTTSService(TTSService): **kwargs, ) - self._lang_code = language_to_kokoro_language(_params.language) + self._lang_code = default_settings.lang_code - 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() diff --git a/src/pipecat/services/lmnt/tts.py b/src/pipecat/services/lmnt/tts.py index a8ccec358..c69eadfef 100644 --- a/src/pipecat/services/lmnt/tts.py +++ b/src/pipecat/services/lmnt/tts.py @@ -125,17 +125,25 @@ class LmntTTSService(InterruptibleTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "LmntTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "LmntTTSSettings", "model") - + # 1. Initialize default_settings with hardcoded defaults default_settings = LmntTTSSettings( - model=model or "blizzard", - voice=voice_id, + model="blizzard", + voice=None, language=self.language_to_service_language(language), format="raw", ) + + # 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) diff --git a/src/pipecat/services/minimax/tts.py b/src/pipecat/services/minimax/tts.py index 9e520f763..2d9f49636 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, ClassVar, Dict, Mapping, Optional, Self import aiohttp from loguru import logger @@ -123,7 +123,7 @@ class MiniMaxTTSSettings(TTSSettings): _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 @@ -245,74 +245,82 @@ class MiniMaxHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if model is not None: - _warn_deprecated_param("model", "MiniMaxTTSSettings", "model") - if voice_id is not None: - _warn_deprecated_param("voice_id", "MiniMaxTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "MiniMaxTTSSettings") - - _params = params or MiniMaxHttpTTSService.InputParams() - - # Resolve language boost - language_boost = None - if _params.language: - service_lang = self.language_to_service_language(_params.language) - if service_lang: - language_boost = service_lang - - # Resolve emotion - emotion = None - if _params.emotion: - supported_emotions = [ - "happy", - "sad", - "angry", - "fearful", - "disgusted", - "surprised", - "neutral", - "fluent", - ] - if _params.emotion in supported_emotions: - emotion = _params.emotion - else: - logger.warning( - f"Unsupported emotion: {_params.emotion}. Supported emotions: {supported_emotions}" - ) - - # Resolve text_normalization - text_normalization = None - 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, - ) - text_normalization = _params.english_normalization - if _params.text_normalization is not None: - text_normalization = _params.text_normalization - + # 1. Initialize default_settings with hardcoded defaults default_settings = MiniMaxTTSSettings( - model=model or "speech-02-turbo", - voice=voice_id or "Calm_Woman", + model="speech-02-turbo", + voice="Calm_Woman", language=None, stream=True, - speed=_params.speed, - volume=_params.volume, - pitch=_params.pitch, - language_boost=language_boost, - emotion=emotion, - text_normalization=text_normalization, - latex_read=_params.latex_read, + speed=1.0, + volume=1.0, + pitch=0, + language_boost=None, + emotion=None, + text_normalization=None, + latex_read=None, audio_bitrate=128000, audio_format="pcm", audio_channel=1, audio_sample_rate=0, ) + + # 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) diff --git a/src/pipecat/services/mistral/llm.py b/src/pipecat/services/mistral/llm.py index da1f612c9..ca72cde37 100644 --- a/src/pipecat/services/mistral/llm.py +++ b/src/pipecat/services/mistral/llm.py @@ -48,10 +48,15 @@ class MistralLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="mistral-small-latest") - default_settings = OpenAILLMSettings(model=model or "mistral-small-latest") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/moondream/vision.py b/src/pipecat/services/moondream/vision.py index b80928a43..3f0701c80 100644 --- a/src/pipecat/services/moondream/vision.py +++ b/src/pipecat/services/moondream/vision.py @@ -102,10 +102,15 @@ class MoondreamService(VisionService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent VisionService. """ - if model is not None: - _warn_deprecated_param("model", "MoondreamSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = MoondreamSettings(model="vikhyatk/moondream2") - default_settings = MoondreamSettings(model=model or "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) diff --git a/src/pipecat/services/neuphonic/tts.py b/src/pipecat/services/neuphonic/tts.py index e1efee96b..ae85c3ab5 100644 --- a/src/pipecat/services/neuphonic/tts.py +++ b/src/pipecat/services/neuphonic/tts.py @@ -154,21 +154,31 @@ class NeuphonicTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "NeuphonicTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "NeuphonicTTSSettings") - - _params = params or NeuphonicTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = NeuphonicTTSSettings( model=None, - language=self.language_to_service_language(_params.language), - speed=_params.speed, + voice=None, + language=self.language_to_service_language(Language.EN), + speed=1.0, encoding=encoding, sampling_rate=sample_rate, - voice=voice_id, ) + + # 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) @@ -487,21 +497,33 @@ class NeuphonicHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "NeuphonicTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "NeuphonicTTSSettings") - - _params = params or NeuphonicHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = NeuphonicTTSSettings( model=None, - voice=voice_id, - language=self.language_to_service_language(_params.language) or "en", - speed=_params.speed, + voice=None, + language=self.language_to_service_language(Language.EN) or "en", + speed=1.0, encoding=encoding, sampling_rate=sample_rate, ) + + # 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) diff --git a/src/pipecat/services/nvidia/llm.py b/src/pipecat/services/nvidia/llm.py index 1667457b9..f09db54fa 100644 --- a/src/pipecat/services/nvidia/llm.py +++ b/src/pipecat/services/nvidia/llm.py @@ -52,12 +52,15 @@ class NvidiaLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="nvidia/llama-3.1-nemotron-70b-instruct") - default_settings = OpenAILLMSettings( - model=model or "nvidia/llama-3.1-nemotron-70b-instruct" - ) + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/nvidia/stt.py b/src/pipecat/services/nvidia/stt.py index 63e901005..3ceaf45fa 100644 --- a/src/pipecat/services/nvidia/stt.py +++ b/src/pipecat/services/nvidia/stt.py @@ -174,15 +174,21 @@ class NvidiaSTTService(STTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - if params is not None: - _warn_deprecated_param("params", "NvidiaSTTSettings") - - _params = params or NvidiaSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = NvidiaSTTSettings( model=model_function_map.get("model_name"), - language=_params.language, + 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) @@ -492,21 +498,33 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService """ - if params is not None: - _warn_deprecated_param("params", "NvidiaSegmentedSTTSettings") - - _params = params or NvidiaSegmentedSTTService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_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, + 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) diff --git a/src/pipecat/services/nvidia/tts.py b/src/pipecat/services/nvidia/tts.py index 75caa27e4..be0b90071 100644 --- a/src/pipecat/services/nvidia/tts.py +++ b/src/pipecat/services/nvidia/tts.py @@ -117,19 +117,29 @@ class NvidiaTTSService(TTSService): use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "NvidiaTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "NvidiaTTSSettings") - - _params = params or NvidiaTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = NvidiaTTSSettings( model=model_function_map.get("model_name"), - voice=voice_id or "Magpie-Multilingual.EN-US.Aria", - language=_params.language, - quality=_params.quality, + 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) diff --git a/src/pipecat/services/ollama/llm.py b/src/pipecat/services/ollama/llm.py index 8fc94985d..2a4a3e78f 100644 --- a/src/pipecat/services/ollama/llm.py +++ b/src/pipecat/services/ollama/llm.py @@ -44,10 +44,15 @@ class OLLamaLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="llama2") - default_settings = OpenAILLMSettings(model=model or "llama2") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/openai/base_llm.py b/src/pipecat/services/openai/base_llm.py index 912b3f0b1..e3c3676c3 100644 --- a/src/pipecat/services/openai/base_llm.py +++ b/src/pipecat/services/openai/base_llm.py @@ -150,24 +150,41 @@ class BaseOpenAILLMService(LLMService): 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=model or "gpt-4o", - frequency_penalty=_params.frequency_penalty, - presence_penalty=_params.presence_penalty, - seed=_params.seed, - temperature=_params.temperature, - top_p=_params.top_p, + model="gpt-4o", + frequency_penalty=NOT_GIVEN, + presence_penalty=NOT_GIVEN, + seed=NOT_GIVEN, + temperature=NOT_GIVEN, + top_p=NOT_GIVEN, top_k=None, - max_tokens=_params.max_tokens, - max_completion_tokens=_params.max_completion_tokens, - service_tier=_params.service_tier, + max_tokens=NOT_GIVEN, + max_completion_tokens=NOT_GIVEN, + service_tier=NOT_GIVEN, filter_incomplete_user_turns=False, user_turn_completion_config=None, - extra=_params.extra if isinstance(_params.extra, dict) else {}, + 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 + default_settings.service_tier = params.service_tier + 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) diff --git a/src/pipecat/services/openai/image.py b/src/pipecat/services/openai/image.py index a145df6e5..fd9bd0ba8 100644 --- a/src/pipecat/services/openai/image.py +++ b/src/pipecat/services/openai/image.py @@ -70,10 +70,15 @@ class OpenAIImageGenService(ImageGenService): settings: Runtime-updatable settings. When provided alongside deprecated parameters, ``settings`` values take precedence. """ - if model is not None: - _warn_deprecated_param("model", "OpenAIImageGenSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAIImageGenSettings(model="dall-e-3") - default_settings = OpenAIImageGenSettings(model=model or "dall-e-3") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIImageGenSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/openai/llm.py b/src/pipecat/services/openai/llm.py index a8ab760c4..56515ce89 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, @@ -95,27 +97,44 @@ class OpenAILLMService(BaseOpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent BaseOpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") - if params is not None: - _warn_deprecated_param("params", "OpenAILLMSettings") - - _params = params or BaseOpenAILLMService.InputParams() + # 1. Initialize default_settings with hardcoded defaults default_settings = OpenAILLMSettings( - model=model or "gpt-4.1", - frequency_penalty=_params.frequency_penalty, - presence_penalty=_params.presence_penalty, - seed=_params.seed, - temperature=_params.temperature, - top_p=_params.top_p, + model="gpt-4.1", + frequency_penalty=NOT_GIVEN, + presence_penalty=NOT_GIVEN, + seed=NOT_GIVEN, + temperature=NOT_GIVEN, + top_p=NOT_GIVEN, top_k=None, - max_tokens=_params.max_tokens, - max_completion_tokens=_params.max_completion_tokens, - service_tier=_params.service_tier, + max_tokens=NOT_GIVEN, + max_completion_tokens=NOT_GIVEN, + service_tier=NOT_GIVEN, filter_incomplete_user_turns=False, user_turn_completion_config=None, - extra=_params.extra if isinstance(_params.extra, dict) else {}, + extra={}, ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 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 + default_settings.service_tier = params.service_tier + 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) diff --git a/src/pipecat/services/openai/realtime/llm.py b/src/pipecat/services/openai/realtime/llm.py index d6e7a71bd..1230ed2db 100644 --- a/src/pipecat/services/openai/realtime/llm.py +++ b/src/pipecat/services/openai/realtime/llm.py @@ -168,12 +168,6 @@ class OpenAIRealtimeLLMService(LLMService): **kwargs: Additional arguments passed to parent LLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAIRealtimeLLMSettings", "model") - if session_properties is not None: - _warn_deprecated_param( - "session_properties", "OpenAIRealtimeLLMSettings", "session_properties" - ) if send_transcription_frames is not None: import warnings @@ -186,8 +180,9 @@ class OpenAIRealtimeLLMService(LLMService): stacklevel=2, ) + # 1. Initialize default_settings with hardcoded defaults default_settings = OpenAIRealtimeLLMSettings( - model=model or "gpt-realtime-1.5", + model="gpt-realtime-1.5", temperature=None, max_tokens=None, top_p=None, @@ -197,8 +192,20 @@ class OpenAIRealtimeLLMService(LLMService): seed=None, filter_incomplete_user_turns=False, user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), + session_properties=events.SessionProperties(), ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeLLMSettings, "model") + default_settings.model = model + if session_properties is not None: + _warn_deprecated_param( + "session_properties", OpenAIRealtimeLLMSettings, "session_properties" + ) + default_settings.session_properties = session_properties + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/openai/stt.py b/src/pipecat/services/openai/stt.py index 5c31d3f02..ea2814619 100644 --- a/src/pipecat/services/openai/stt.py +++ b/src/pipecat/services/openai/stt.py @@ -94,23 +94,35 @@ class OpenAISTTService(BaseWhisperSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ - if model is not None: - _warn_deprecated_param("model", "BaseWhisperSTTSettings", "model") - - super().__init__( - model=model or "gpt-4o-transcribe", - api_key=api_key, + # --- 1. Hardcoded defaults --- + _language = language or Language.EN + default_settings = BaseWhisperSTTSettings( + model="gpt-4o-transcribe", + language=self.language_to_service_language(_language), base_url=base_url, - language=language, prompt=prompt, temperature=temperature, + ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", BaseWhisperSTTSettings, "model") + default_settings.model = model + + # --- 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__( + api_key=api_key, + base_url=base_url, + settings=default_settings, ttfs_p99_latency=ttfs_p99_latency, **kwargs, ) - if settings is not None: - self._settings.apply_update(settings) - async def _transcribe(self, audio: bytes) -> Transcription: assert self._language is not None # Assigned in the BaseWhisperSTTService class @@ -242,14 +254,21 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): "Install it with: pip install pipecat-ai[openai]" ) - if model is not None: - _warn_deprecated_param("model", "OpenAIRealtimeSTTSettings", "model") - + # --- 1. Hardcoded defaults --- default_settings = OpenAIRealtimeSTTSettings( - model=model or "gpt-4o-transcribe", + model="gpt-4o-transcribe", language=language, prompt=prompt, ) + + # --- 2. Deprecated direct-arg overrides --- + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeSTTSettings, "model") + default_settings.model = model + + # --- 3. (no params object for this service) --- + + # --- 4. Settings delta (canonical API, always wins) --- if settings is not None: default_settings.apply_update(settings) @@ -262,7 +281,7 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): self._api_key = api_key self._base_url = base_url - self._prompt = prompt + self._prompt = self._settings.prompt self._turn_detection = turn_detection self._noise_reduction = noise_reduction self._should_interrupt = should_interrupt diff --git a/src/pipecat/services/openai/tts.py b/src/pipecat/services/openai/tts.py index 42c963808..a119c3d14 100644 --- a/src/pipecat/services/openai/tts.py +++ b/src/pipecat/services/openai/tts.py @@ -150,34 +150,43 @@ class OpenAITTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to TTSService. """ - if voice is not None: - _warn_deprecated_param("voice", "OpenAITTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "OpenAITTSSettings", "model") - if instructions is not None: - _warn_deprecated_param("instructions", "OpenAITTSSettings", "instructions") - if speed is not None: - _warn_deprecated_param("speed", "OpenAITTSSettings", "speed") - if params is not None: - _warn_deprecated_param("params", "OpenAITTSSettings") - 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." ) - _params = params or OpenAITTSService.InputParams() - _instructions = instructions if instructions is not None else _params.instructions - _speed = speed if speed is not None else _params.speed - + # 1. Initialize default_settings with hardcoded defaults default_settings = OpenAITTSSettings( - model=model or "gpt-4o-mini-tts", - voice=voice or "alloy", + model="gpt-4o-mini-tts", + voice="alloy", language=None, - instructions=_instructions, - speed=_speed, ) + + # 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) diff --git a/src/pipecat/services/openai_realtime_beta/openai.py b/src/pipecat/services/openai_realtime_beta/openai.py index cb660ce72..11b60c3b9 100644 --- a/src/pipecat/services/openai_realtime_beta/openai.py +++ b/src/pipecat/services/openai_realtime_beta/openai.py @@ -167,15 +167,9 @@ class OpenAIRealtimeBetaLLMService(LLMService): stacklevel=2, ) - if model is not None: - _warn_deprecated_param("model", "OpenAIRealtimeBetaLLMSettings", "model") - if session_properties is not None: - _warn_deprecated_param( - "session_properties", "OpenAIRealtimeBetaLLMSettings", "session_properties" - ) - + # 1. Initialize default_settings with hardcoded defaults default_settings = OpenAIRealtimeBetaLLMSettings( - model=model or "gpt-4o-realtime-preview-2025-06-03", + model="gpt-4o-realtime-preview-2025-06-03", temperature=None, max_tokens=None, top_p=None, @@ -185,8 +179,20 @@ class OpenAIRealtimeBetaLLMService(LLMService): seed=None, filter_incomplete_user_turns=False, user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), + session_properties=events.SessionProperties(), ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAIRealtimeBetaLLMSettings, "model") + default_settings.model = model + if session_properties is not None: + _warn_deprecated_param( + "session_properties", OpenAIRealtimeBetaLLMSettings, "session_properties" + ) + default_settings.session_properties = session_properties + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/openpipe/llm.py b/src/pipecat/services/openpipe/llm.py index 7fb4ebd2d..9724c0a3f 100644 --- a/src/pipecat/services/openpipe/llm.py +++ b/src/pipecat/services/openpipe/llm.py @@ -64,10 +64,15 @@ class OpenPipeLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="gpt-4.1") - default_settings = OpenAILLMSettings(model=model or "gpt-4.1") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/openrouter/llm.py b/src/pipecat/services/openrouter/llm.py index ea307aaee..42f01c77d 100644 --- a/src/pipecat/services/openrouter/llm.py +++ b/src/pipecat/services/openrouter/llm.py @@ -50,10 +50,15 @@ class OpenRouterLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="openai/gpt-4o-2024-11-20") - default_settings = OpenAILLMSettings(model=model or "openai/gpt-4o-2024-11-20") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/perplexity/llm.py b/src/pipecat/services/perplexity/llm.py index 1fbf763f3..2d350b736 100644 --- a/src/pipecat/services/perplexity/llm.py +++ b/src/pipecat/services/perplexity/llm.py @@ -53,10 +53,15 @@ class PerplexityLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="sonar") - default_settings = OpenAILLMSettings(model=model or "sonar") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/piper/tts.py b/src/pipecat/services/piper/tts.py index 73c555c9d..fd6b0bf16 100644 --- a/src/pipecat/services/piper/tts.py +++ b/src/pipecat/services/piper/tts.py @@ -76,10 +76,17 @@ class PiperTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent `TTSService`. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "PiperTTSSettings", "voice") + # 1. Initialize default_settings with hardcoded defaults + default_settings = PiperTTSSettings(model=None, voice=None, language=None) - default_settings = PiperTTSSettings(model=None, voice=voice_id, 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) @@ -92,15 +99,15 @@ class PiperTTSService(TTSService): _voice = self._settings.voice model_file = f"{_voice}.onnx" - model_path = Path(download_dir) / model_file + model_path_resolved = Path(download_dir) / model_file - if not model_path.exists(): + 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}' 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}' model") @@ -222,10 +229,17 @@ class PiperHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "PiperHttpTTSSettings", "voice") + # 1. Initialize default_settings with hardcoded defaults + default_settings = PiperHttpTTSSettings(model=None, voice=None, language=None) - default_settings = PiperHttpTTSSettings(model=None, voice=voice_id, 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) diff --git a/src/pipecat/services/qwen/llm.py b/src/pipecat/services/qwen/llm.py index db407f880..92d24fa76 100644 --- a/src/pipecat/services/qwen/llm.py +++ b/src/pipecat/services/qwen/llm.py @@ -45,10 +45,15 @@ class QwenLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="qwen-plus") - default_settings = OpenAILLMSettings(model=model or "qwen-plus") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/resembleai/tts.py b/src/pipecat/services/resembleai/tts.py index ade4361e0..28ec8a522 100644 --- a/src/pipecat/services/resembleai/tts.py +++ b/src/pipecat/services/resembleai/tts.py @@ -95,17 +95,30 @@ class ResembleAITTSService(AudioContextTTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "ResembleAITTSSettings", "voice") - + # 1. Initialize default_settings with hardcoded defaults default_settings = ResembleAITTSSettings( model=None, - voice=voice_id, + voice=None, language=None, - precision=precision, - output_format=output_format, - resemble_sample_rate=sample_rate, + precision="PCM_16", + output_format="wav", + resemble_sample_rate=22050, ) + + # 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 + if precision is not None: + default_settings.precision = precision + if output_format is not None: + default_settings.output_format = output_format + if sample_rate is not None: + default_settings.resemble_sample_rate = sample_rate + + # 3. No params for this service + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/rime/tts.py b/src/pipecat/services/rime/tts.py index c607a2e06..1de4087de 100644 --- a/src/pipecat/services/rime/tts.py +++ b/src/pipecat/services/rime/tts.py @@ -226,38 +226,57 @@ class RimeTTSService(AudioContextTTSService): **kwargs: Additional arguments passed to parent class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "RimeTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "RimeTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "RimeTTSSettings") - - # 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=model or "arcana", - voice=voice_id, + model="arcana", + voice=None, 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, + language=None, + segment=None, + inlineSpeedAlpha=None, + speedAlpha=None, # Arcana params - repetition_penalty=_params.repetition_penalty, - temperature=_params.temperature, - top_p=_params.top_p, + repetition_penalty=None, + temperature=None, + top_p=None, # 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, + 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) @@ -713,35 +732,50 @@ class RimeHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "RimeTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "RimeTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "RimeTTSSettings") - - _params = params or RimeHttpTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = RimeTTSSettings( - model=model or "mistv2", - language=self.language_to_service_language(_params.language) - if _params.language - else "eng", + model="mistv2", + voice=None, + language="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, + speedAlpha=None, + reduceLatency=None, + pauseBetweenBrackets=None, + phonemizeBetweenBrackets=None, noTextNormalization=None, saveOovs=None, - inlineSpeedAlpha=_params.inline_speed_alpha if _params.inline_speed_alpha else None, + inlineSpeedAlpha=None, repetition_penalty=None, temperature=None, top_p=None, - voice=voice_id, ) + + # 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) @@ -936,28 +970,40 @@ class RimeNonJsonTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent class. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "RimeNonJsonTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "RimeNonJsonTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "RimeNonJsonTTSSettings") - - _params = params or RimeNonJsonTTSService.InputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = RimeNonJsonTTSSettings( - voice=voice_id, - model=model or "arcana", + voice=None, + model="arcana", 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, + 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) @@ -974,8 +1020,8 @@ class RimeNonJsonTTSService(InterruptibleTTSService): self._api_key = api_key self._url = url # Add any extra parameters for future compatibility - if _params.extra: - self._settings.extra.update(_params.extra) + if params and params.extra: + self._settings.extra.update(params.extra) self._receive_task = None self._context_id: Optional[str] = None diff --git a/src/pipecat/services/sambanova/llm.py b/src/pipecat/services/sambanova/llm.py index 5114297a8..f9b7b1380 100644 --- a/src/pipecat/services/sambanova/llm.py +++ b/src/pipecat/services/sambanova/llm.py @@ -57,10 +57,15 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="Llama-4-Maverick-17B-128E-Instruct") - default_settings = OpenAILLMSettings(model=model or "Llama-4-Maverick-17B-128E-Instruct") + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/sambanova/stt.py b/src/pipecat/services/sambanova/stt.py index 4ca156b88..0c2d77e36 100644 --- a/src/pipecat/services/sambanova/stt.py +++ b/src/pipecat/services/sambanova/stt.py @@ -71,27 +71,30 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to `pipecat.services.whisper.base_stt.BaseWhisperSTTService`. """ - if model is not None: - _warn_deprecated_param("model", "BaseWhisperSTTSettings", "model") - if language is not None: - _warn_deprecated_param("language", "BaseWhisperSTTSettings", "language") - if prompt is not None: - _warn_deprecated_param("prompt", "BaseWhisperSTTSettings", "prompt") - if temperature is not None: - _warn_deprecated_param("temperature", "BaseWhisperSTTSettings", "temperature") - - model = model or "Whisper-Large-v3" - language = language or Language.EN - - # Build settings from deprecated params and pass via settings= - # to avoid double deprecation warnings in BaseWhisperSTTService. + # --- 1. Hardcoded defaults --- default_settings = BaseWhisperSTTSettings( - model=model, - language=self.language_to_service_language(language), + model="Whisper-Large-v3", + language=self.language_to_service_language(Language.EN), base_url=base_url, - prompt=prompt, - temperature=temperature, ) + + # --- 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) diff --git a/src/pipecat/services/sarvam/stt.py b/src/pipecat/services/sarvam/stt.py index 97c8d1ccc..fd9a55f14 100644 --- a/src/pipecat/services/sarvam/stt.py +++ b/src/pipecat/services/sarvam/stt.py @@ -238,44 +238,56 @@ class SarvamSTTService(STTService): keepalive_interval: Seconds between idle checks when keepalive is enabled. **kwargs: Additional arguments passed to the parent STTService. """ + # 1. Initialize default_settings with hardcoded defaults + default_settings = SarvamSTTSettings( + model="saarika:v2.5", + language=None, + prompt=None, + mode=None, + vad_signals=None, + high_vad_sensitivity=None, + ) + + # 2. Apply direct init arg overrides (deprecated) if model is not None: - _warn_deprecated_param("model", "SarvamSTTSettings", "model") + _warn_deprecated_param("model", SarvamSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided if params is not None: - _warn_deprecated_param("params", "SarvamSTTSettings") + _warn_deprecated_param("params", SarvamSTTSettings) + if not settings: + default_settings.language = params.language + default_settings.prompt = params.prompt + default_settings.mode = params.mode + default_settings.vad_signals = params.vad_signals + default_settings.high_vad_sensitivity = params.high_vad_sensitivity - model = model or "saarika:v2.5" - _params = params or SarvamSTTService.InputParams() + # 4. Apply settings delta (canonical API, always wins) + if settings is not None: + default_settings.apply_update(settings) - # Get model configuration (validates model exists) - if model not in MODEL_CONFIGS: + # 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 default_settings.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 - - default_settings = SarvamSTTSettings( - model=model, - language=_params.language, - prompt=_params.prompt, - mode=mode, - vad_signals=_params.vad_signals, - high_vad_sensitivity=_params.high_vad_sensitivity, - ) - if settings is not None: - default_settings.apply_update(settings) + if default_settings.mode is None: + default_settings.mode = self._config.default_mode super().__init__( sample_rate=sample_rate, @@ -301,7 +313,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") diff --git a/src/pipecat/services/sarvam/tts.py b/src/pipecat/services/sarvam/tts.py index 14386d743..8c76e0ec9 100644 --- a/src/pipecat/services/sarvam/tts.py +++ b/src/pipecat/services/sarvam/tts.py @@ -467,55 +467,89 @@ class SarvamHttpTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "SarvamHttpTTSSettings", "voice") - if model is not None: - _warn_deprecated_param("model", "SarvamHttpTTSSettings", "model") - if params is not None: - _warn_deprecated_param("params", "SarvamHttpTTSSettings") + # 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, + ) - model = model or "bulbul:v2" + # 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) - if model not in TTS_MODEL_CONFIGS: + 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 '{model}'. Allowed values: {allowed}.") + raise ValueError(f"Unsupported model '{resolved_model}'. Allowed values: {allowed}.") - self._config = TTS_MODEL_CONFIGS[model] + 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)) - default_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, - ) - if settings is not None: - default_settings.apply_update(settings) + # 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, @@ -527,22 +561,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. @@ -858,62 +876,105 @@ class SarvamTTSService(InterruptibleTTSService): See https://docs.sarvam.ai/api-reference-docs/text-to-speech/stream """ - if model is not None: - _warn_deprecated_param("model", "SarvamTTSSettings", "model") - if voice_id is not None: - _warn_deprecated_param("voice_id", "SarvamTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "SarvamTTSSettings") + # 1. Initialize default_settings with hardcoded defaults + default_settings = SarvamTTSSettings( + model="bulbul:v2", + voice="anushka", + language="en-IN", + speech_sample_rate="22050", + enable_preprocessing=False, + min_buffer_size=50, + max_chunk_length=150, + output_audio_codec="linear16", + output_audio_bitrate="128k", + pace=1.0, + pitch=None, + loudness=None, + temperature=None, + ) - model = model or "bulbul:v2" + # 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 + + # 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: + default_settings.output_audio_codec = params.output_audio_codec + if params.output_audio_bitrate is not None: + default_settings.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) - if model not in TTS_MODEL_CONFIGS: + 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 '{model}'. Allowed values: {allowed}.") + raise ValueError(f"Unsupported model '{resolved_model}'. Allowed values: {allowed}.") - self._config = TTS_MODEL_CONFIGS[model] + 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 + default_settings.speech_sample_rate = str(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)) - default_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, - ) - if settings is not None: - default_settings.apply_update(settings) + # Force preprocessing for models that require it + if self._config.preprocessing_always_enabled: + default_settings.enable_preprocessing = True - # Initialize parent class first + # 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, @@ -926,25 +987,9 @@ class SarvamTTSService(InterruptibleTTSService): ) # 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 diff --git a/src/pipecat/services/settings.py b/src/pipecat/services/settings.py index 546104b9a..d9ec5bc7b 100644 --- a/src/pipecat/services/settings.py +++ b/src/pipecat/services/settings.py @@ -56,7 +56,7 @@ if TYPE_CHECKING: def _warn_deprecated_param( param_name: str, - settings_class_name: str, + settings_class: type, settings_field: str | None = None, stacklevel: int = 3, ): @@ -64,12 +64,13 @@ def _warn_deprecated_param( Args: param_name: Name of the deprecated parameter. - settings_class_name: Name of the settings class to use instead. + 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. " diff --git a/src/pipecat/services/soniox/stt.py b/src/pipecat/services/soniox/stt.py index c9b3fb7c9..b37a76b0f 100644 --- a/src/pipecat/services/soniox/stt.py +++ b/src/pipecat/services/soniox/stt.py @@ -218,25 +218,42 @@ class SonioxSTTService(WebsocketSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService. """ - if model is not None: - _warn_deprecated_param("model", "SonioxSTTSettings", "model") - if params is not None: - _warn_deprecated_param("params", "SonioxSTTSettings") - - _params = params or SonioxInputParams() - + # 1. Initialize default_settings with hardcoded defaults default_settings = SonioxSTTSettings( - model=model or _params.model, + model="stt-rt-v4", 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, + audio_format="pcm_s16le", + num_channels=1, + language_hints=None, + language_hints_strict=None, + context=None, + enable_speaker_diarization=False, + enable_language_identification=False, + client_reference_id=None, ) + + # 2. Apply direct init arg overrides (deprecated) + if model is not None: + _warn_deprecated_param("model", SonioxSTTSettings, "model") + default_settings.model = model + + # 3. Apply params overrides — only if settings not provided + if params is not None: + _warn_deprecated_param("params", SonioxSTTSettings) + if not settings: + default_settings.model = params.model + default_settings.audio_format = params.audio_format + default_settings.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. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/speechmatics/stt.py b/src/pipecat/services/speechmatics/stt.py index 2d3e90896..620646d31 100644 --- a/src/pipecat/services/speechmatics/stt.py +++ b/src/pipecat/services/speechmatics/stt.py @@ -417,57 +417,86 @@ class SpeechmaticsSTTService(STTService): if not self._base_url: raise ValueError("Missing Speechmatics base URL") - if params is not None: - _warn_deprecated_param("params", "SpeechmaticsSTTSettings") - - # 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 + # 1. Initialize default_settings with 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=[], + audio_encoding=AudioEncoding.PCM_S16LE, + 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. Apply params overrides — only if settings not provided + 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 + default_settings.audio_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(default_settings) default_settings.model = self._config.operating_point.value + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) @@ -496,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") # ============================================================================ diff --git a/src/pipecat/services/speechmatics/tts.py b/src/pipecat/services/speechmatics/tts.py index 8ce6ae2ef..dff3e5f0f 100644 --- a/src/pipecat/services/speechmatics/tts.py +++ b/src/pipecat/services/speechmatics/tts.py @@ -104,24 +104,32 @@ class SpeechmaticsTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "SpeechmaticsTTSSettings", "voice") - if params is not None: - _warn_deprecated_param("params", "SpeechmaticsTTSSettings") - if sample_rate and sample_rate != self.SPEECHMATICS_SAMPLE_RATE: logger.warning( 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=voice_id or "sarah", + voice="sarah", language=None, - max_retries=_params.max_retries, + 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) diff --git a/src/pipecat/services/together/llm.py b/src/pipecat/services/together/llm.py index 48e15ae5c..0fd8b637b 100644 --- a/src/pipecat/services/together/llm.py +++ b/src/pipecat/services/together/llm.py @@ -45,12 +45,15 @@ class TogetherLLMService(OpenAILLMService): parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - if model is not None: - _warn_deprecated_param("model", "OpenAILLMSettings", "model") + # 1. Initialize default_settings with hardcoded defaults + default_settings = OpenAILLMSettings(model="meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo") - default_settings = OpenAILLMSettings( - model=model or "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", OpenAILLMSettings, "model") + default_settings.model = model + + # 4. Apply settings delta (canonical API, always wins) if settings is not None: default_settings.apply_update(settings) diff --git a/src/pipecat/services/ultravox/llm.py b/src/pipecat/services/ultravox/llm.py index 933930152..094d22827 100644 --- a/src/pipecat/services/ultravox/llm.py +++ b/src/pipecat/services/ultravox/llm.py @@ -186,6 +186,7 @@ class UltravoxRealtimeLLMService(LLMService): 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, temperature=None, @@ -199,6 +200,10 @@ class UltravoxRealtimeLLMService(LLMService): 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) diff --git a/src/pipecat/services/whisper/base_stt.py b/src/pipecat/services/whisper/base_stt.py index a4eee299b..91bc54633 100644 --- a/src/pipecat/services/whisper/base_stt.py +++ b/src/pipecat/services/whisper/base_stt.py @@ -174,24 +174,30 @@ class BaseWhisperSTTService(SegmentedSTTService): Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - if model is not None: - _warn_deprecated_param("model", "BaseWhisperSTTSettings", "model") - if language is not None: - _warn_deprecated_param("language", "BaseWhisperSTTSettings", "language") - if prompt is not None: - _warn_deprecated_param("prompt", "BaseWhisperSTTSettings", "prompt") - if temperature is not None: - _warn_deprecated_param("temperature", "BaseWhisperSTTSettings", "temperature") - - _language = language or Language.EN - + # --- 1. Hardcoded defaults --- default_settings = BaseWhisperSTTSettings( - model=model, - language=self.language_to_service_language(_language), + model=None, + language=None, base_url=base_url, - prompt=prompt, - temperature=temperature, ) + + # --- 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) @@ -202,10 +208,8 @@ class BaseWhisperSTTService(SegmentedSTTService): ) self._client = self._create_client(api_key, base_url) self._language = self._settings.language - self._prompt = self._settings.prompt if self._settings.prompt else prompt - self._temperature = ( - self._settings.temperature if self._settings.temperature else temperature - ) + self._prompt = self._settings.prompt + self._temperature = self._settings.temperature self._include_prob_metrics = include_prob_metrics def _create_client(self, api_key: Optional[str], base_url: Optional[str]): diff --git a/src/pipecat/services/whisper/stt.py b/src/pipecat/services/whisper/stt.py index 38fd287fa..17fe24c2d 100644 --- a/src/pipecat/services/whisper/stt.py +++ b/src/pipecat/services/whisper/stt.py @@ -256,30 +256,35 @@ class WhisperSTTService(SegmentedSTTService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to SegmentedSTTService. """ - if model is not None: - _warn_deprecated_param("model", "WhisperSTTSettings", "model") - if device is not None: - _warn_deprecated_param("device", "WhisperSTTSettings", "device") - if compute_type is not None: - _warn_deprecated_param("compute_type", "WhisperSTTSettings", "compute_type") - if no_speech_prob is not None: - _warn_deprecated_param("no_speech_prob", "WhisperSTTSettings", "no_speech_prob") - if language is not None: - _warn_deprecated_param("language", "WhisperSTTSettings", "language") - - _model = model if model is not None else Model.DISTIL_MEDIUM_EN - _device = device or "auto" - _compute_type = compute_type or "default" - _no_speech_prob = no_speech_prob if no_speech_prob is not None else 0.4 - _language = language or Language.EN - + # --- 1. Hardcoded defaults --- default_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, + model=Model.DISTIL_MEDIUM_EN.value, + language=Language.EN, + device="auto", + compute_type="default", + 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 device is not None: + _warn_deprecated_param("device", WhisperSTTSettings, "device") + default_settings.device = device + if compute_type is not None: + _warn_deprecated_param("compute_type", WhisperSTTSettings, "compute_type") + default_settings.compute_type = compute_type + 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) @@ -430,27 +435,32 @@ class WhisperSTTServiceMLX(WhisperSTTService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to SegmentedSTTService. """ - if model is not None: - _warn_deprecated_param("model", "WhisperMLXSTTSettings", "model") - if no_speech_prob is not None: - _warn_deprecated_param("no_speech_prob", "WhisperMLXSTTSettings", "no_speech_prob") - if language is not None: - _warn_deprecated_param("language", "WhisperMLXSTTSettings", "language") - if temperature is not None: - _warn_deprecated_param("temperature", "WhisperMLXSTTSettings", "temperature") - - _model = model if model is not None else MLXModel.TINY - _no_speech_prob = no_speech_prob if no_speech_prob is not None else 0.6 - _language = language or Language.EN - _temperature = temperature if temperature is not None else 0.0 - + # --- 1. Hardcoded defaults --- default_settings = WhisperMLXSTTSettings( - model=_model if isinstance(_model, str) else _model.value, - language=_language, - no_speech_prob=_no_speech_prob, - temperature=_temperature, + 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) diff --git a/src/pipecat/services/xtts/tts.py b/src/pipecat/services/xtts/tts.py index 88137172f..c5bfe629e 100644 --- a/src/pipecat/services/xtts/tts.py +++ b/src/pipecat/services/xtts/tts.py @@ -118,15 +118,20 @@ class XTTSService(TTSService): parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - if voice_id is not None: - _warn_deprecated_param("voice_id", "XTTSTTSSettings", "voice") - + # 1. Initialize default_settings with hardcoded defaults default_settings = XTTSTTSSettings( model=None, - voice=voice_id, + voice=None, language=self.language_to_service_language(language), base_url=base_url, ) + + # 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)