diff --git a/src/pipecat/services/anthropic/llm.py b/src/pipecat/services/anthropic/llm.py index 755ca6400..67777e049 100644 --- a/src/pipecat/services/anthropic/llm.py +++ b/src/pipecat/services/anthropic/llm.py @@ -58,7 +58,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService from pipecat.services.settings import NOT_GIVEN as _NOT_GIVEN -from pipecat.services.settings import LLMSettings, _NotGiven, is_given +from pipecat.services.settings import LLMSettings, _NotGiven, _warn_deprecated_param, is_given from pipecat.utils.tracing.service_decorators import traced_llm try: @@ -170,6 +170,10 @@ class AnthropicLLMService(LLMService): class InputParams(BaseModel): """Input parameters for Anthropic model inference. + .. deprecated:: + Use ``AnthropicLLMSettings`` instead. Pass settings directly via the + ``settings`` parameter of :class:`AnthropicLLMService`. + Parameters: enable_prompt_caching: Whether to enable the prompt caching feature. enable_prompt_caching_beta (deprecated): Whether to enable the beta prompt caching feature. @@ -213,8 +217,9 @@ class AnthropicLLMService(LLMService): self, *, api_key: str, - model: str = "claude-sonnet-4-6", + model: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[AnthropicLLMSettings] = None, client=None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, @@ -225,42 +230,66 @@ class AnthropicLLMService(LLMService): Args: api_key: Anthropic API key for authentication. - model: Model name to use. Defaults to "claude-sonnet-4-6". + model: Model name to use. + + .. deprecated:: + Use ``settings=AnthropicLLMSettings(model=...)`` instead. + params: Optional model parameters for inference. + + .. deprecated:: + Use ``settings=AnthropicLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. client: Optional custom Anthropic client instance. retry_timeout_secs: Request timeout in seconds for retry logic. retry_on_timeout: Whether to retry the request once if it times out. system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - params = params or AnthropicLLMService.InputParams() + if model is not None: + _warn_deprecated_param("model", "AnthropicLLMSettings", "model") + if params is not None: + _warn_deprecated_param("params", "AnthropicLLMSettings") - super().__init__( - settings=AnthropicLLMSettings( - model=model, - max_tokens=params.max_tokens, - enable_prompt_caching=( - params.enable_prompt_caching - if params.enable_prompt_caching is not None - else ( - params.enable_prompt_caching_beta - if params.enable_prompt_caching_beta is not None - else False - ) - ), - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - thinking=params.thinking, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), - **kwargs, + _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 + + 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, + 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 {}, ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._client = client or AsyncAnthropic( api_key=api_key ) # if the client is provided, use it and remove it, otherwise create a new one diff --git a/src/pipecat/services/assemblyai/stt.py b/src/pipecat/services/assemblyai/stt.py index c62ae959b..85d4029b7 100644 --- a/src/pipecat/services/assemblyai/stt.py +++ b/src/pipecat/services/assemblyai/stt.py @@ -114,6 +114,7 @@ class AssemblyAISTTService(WebsocketSTTService): vad_force_turn_endpoint: bool = True, should_interrupt: bool = True, speaker_format: Optional[str] = None, + settings: Optional[AssemblyAISTTSettings] = None, ttfs_p99_latency: Optional[float] = ASSEMBLYAI_TTFS_P99, **kwargs, ): @@ -144,6 +145,8 @@ class AssemblyAISTTService(WebsocketSTTService): Use {speaker} for speaker label and {text} for transcript text. Example: "<{speaker}>{text}" or "{speaker}: {text}" If None, transcript text is not modified. Defaults to None. + settings: Runtime-updatable settings. When provided alongside other + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. @@ -185,14 +188,18 @@ class AssemblyAISTTService(WebsocketSTTService): if vad_force_turn_endpoint: connection_params = self._configure_pipecat_turn_mode(connection_params, is_u3_pro) + default_settings = AssemblyAISTTSettings( + model=None, + language=language, + connection_params=connection_params, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=connection_params.sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=AssemblyAISTTSettings( - model=None, - language=language, - connection_params=connection_params, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/asyncai/tts.py b/src/pipecat/services/asyncai/tts.py index 4f1fd5a58..245253ac8 100644 --- a/src/pipecat/services/asyncai/tts.py +++ b/src/pipecat/services/asyncai/tts.py @@ -27,7 +27,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -110,6 +110,9 @@ class AsyncAITTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for Async TTS configuration. + .. deprecated:: 1.0 + Use ``AsyncAITTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -120,14 +123,15 @@ class AsyncAITTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, version: str = "v1", url: str = "wss://api.async.com/text_to_speech/websocket/ws", - model: str = "async_flash_v1.0", + model: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[AsyncAITTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -138,13 +142,27 @@ class AsyncAITTSService(AudioContextTTSService): api_key: Async API key. voice_id: UUID of the voice to use for synthesis. See docs for a full list: https://docs.async.com/list-voices-16699698e0 + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(voice=...)`` instead. + version: Async API version. url: WebSocket URL for Async TTS API. model: TTS model to use (e.g., "async_flash_v1.0"). + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(model=...)`` instead. + sample_rate: Audio sample rate. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -153,7 +171,27 @@ class AsyncAITTSService(AudioContextTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to the parent service. """ - params = params or AsyncAITTSService.InputParams() + 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() + + default_settings = AsyncAITTSSettings( + model=model or "async_flash_v1.0", + voice=voice_id, + output_container=container, + output_encoding=encoding, + output_sample_rate=0, + language=self.language_to_service_language(_params.language) + if _params.language + else None, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -161,16 +199,7 @@ class AsyncAITTSService(AudioContextTTSService): pause_frame_processing=True, push_stop_frames=True, sample_rate=sample_rate, - settings=AsyncAITTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - ), + settings=default_settings, **kwargs, ) @@ -471,6 +500,9 @@ class AsyncAIHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Async API. + .. deprecated:: 1.0 + Use ``AsyncAITTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -481,15 +513,16 @@ class AsyncAIHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "async_flash_v1.0", + model: Optional[str] = None, url: str = "https://api.async.com", version: str = "v1", sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[AsyncAITTSSettings] = None, **kwargs, ): """Initialize the Async TTS service. @@ -497,30 +530,55 @@ class AsyncAIHttpTTSService(TTSService): Args: api_key: Async API key. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(voice=...)`` instead. + aiohttp_session: An aiohttp session for making HTTP requests. model: TTS model to use (e.g., "async_flash_v1.0"). + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(model=...)`` instead. + url: Base URL for Async API. version: API version string for Async API. sample_rate: Audio sample rate. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=AsyncAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - params = params or AsyncAIHttpTTSService.InputParams() + 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() + + default_settings = AsyncAITTSSettings( + model=model or "async_flash_v1.0", + voice=voice_id, + output_container=container, + output_encoding=encoding, + output_sample_rate=0, + language=self.language_to_service_language(_params.language) + if _params.language + else None, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AsyncAITTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/aws/llm.py b/src/pipecat/services/aws/llm.py index 31f8085bc..e244a78ac 100644 --- a/src/pipecat/services/aws/llm.py +++ b/src/pipecat/services/aws/llm.py @@ -55,7 +55,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.utils.tracing.service_decorators import traced_llm try: @@ -752,6 +752,10 @@ class AWSBedrockLLMService(LLMService): class InputParams(BaseModel): """Input parameters for AWS Bedrock LLM service. + .. deprecated:: + Use ``AWSBedrockLLMSettings`` instead. Pass settings directly via the + ``settings`` parameter of :class:`AWSBedrockLLMService`. + Parameters: max_tokens: Maximum number of tokens to generate. temperature: Sampling temperature between 0.0 and 1.0. @@ -771,12 +775,14 @@ class AWSBedrockLLMService(LLMService): def __init__( self, *, - model: str, + model: Optional[str] = None, aws_access_key: Optional[str] = None, aws_secret_key: Optional[str] = None, aws_session_token: Optional[str] = None, aws_region: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[AWSBedrockLLMSettings] = None, + stop_sequences: Optional[List[str]] = None, client_config: Optional[Config] = None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, @@ -787,37 +793,59 @@ class AWSBedrockLLMService(LLMService): Args: model: The AWS Bedrock model identifier to use. + + .. deprecated:: + Use ``settings=AWSBedrockLLMSettings(model=...)`` instead. + aws_access_key: AWS access key ID. If None, uses default credentials. aws_secret_key: AWS secret access key. If None, uses default credentials. aws_session_token: AWS session token for temporary credentials. aws_region: AWS region for the Bedrock service. params: Model parameters and configuration. + + .. deprecated:: + Use ``settings=AWSBedrockLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. + stop_sequences: List of strings that stop generation. client_config: Custom boto3 client configuration. retry_timeout_secs: Request timeout in seconds for retry logic. retry_on_timeout: Whether to retry the request once if it times out. system_instruction: Optional system instruction to use as the system prompt. **kwargs: Additional arguments passed to parent LLMService. """ - params = params or AWSBedrockLLMService.InputParams() + if model is not None: + _warn_deprecated_param("model", "AWSBedrockLLMSettings", "model") + if params is not None: + _warn_deprecated_param("params", "AWSBedrockLLMSettings") - super().__init__( - settings=AWSBedrockLLMSettings( - model=model, - max_tokens=params.max_tokens, - temperature=params.temperature, - top_p=params.top_p, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - latency=params.latency, - additional_model_request_fields=params.additional_model_request_fields - if isinstance(params.additional_model_request_fields, dict) - else {}, - ), - **kwargs, + _params = params or AWSBedrockLLMService.InputParams() + + 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, + 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 {}, + ) + 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 []) ) # Initialize the AWS Bedrock client @@ -843,7 +871,7 @@ class AWSBedrockLLMService(LLMService): self._retry_on_timeout = retry_on_timeout self._system_instruction = system_instruction - logger.info(f"Using AWS Bedrock model: {model}") + logger.info(f"Using AWS Bedrock model: {self._settings.model}") if self._system_instruction: logger.debug(f"{self}: Using system instruction: {self._system_instruction}") diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index 29612e593..887c3f46c 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -60,7 +60,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.utils.time import time_now_iso8601 try: @@ -222,6 +222,7 @@ class AWSNovaSonicLLMService(LLMService): model: str = "amazon.nova-2-sonic-v1:0", voice_id: str = "matthew", params: Optional[Params] = None, + settings: Optional[AWSNovaSonicLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[ToolsSchema] = None, send_transcription_frames: bool = True, @@ -238,12 +239,27 @@ class AWSNovaSonicLLMService(LLMService): - Nova 2 Sonic (the default model): "us-east-1", "us-west-2", "ap-northeast-1" - Nova Sonic (the older model): "us-east-1", "ap-northeast-1" model: Model identifier. Defaults to "amazon.nova-2-sonic-v1:0". + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(model=...)`` instead. + voice_id: Voice ID for speech synthesis. Note that some voices are designed for use with a specific language. Options: - Nova 2 Sonic (the default model): see https://docs.aws.amazon.com/nova/latest/nova2-userguide/sonic-language-support.html - Nova Sonic (the older model): see https://docs.aws.amazon.com/nova/latest/userguide/available-voices.html. + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(voice_id=...)`` instead. + params: Model parameters for audio configuration and inference. + + .. deprecated:: + Use ``settings=AWSNovaSonicLLMSettings(...)`` instead. + + settings: AWS Nova Sonic LLM settings. If provided together with + deprecated top-level parameters, the ``settings`` values take + precedence. system_instruction: System-level instruction for the model. tools: Available tools/functions for the model to use. send_transcription_frames: Whether to emit transcription frames. @@ -254,23 +270,35 @@ class AWSNovaSonicLLMService(LLMService): **kwargs: Additional arguments passed to the parent LLMService. """ - params = params or Params() + # 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() + + default_settings = AWSNovaSonicLLMSettings( + model=model, + voice_id=voice_id, + temperature=_params.temperature, + max_tokens=_params.max_tokens, + top_p=_params.top_p, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + endpointing_sensitivity=_params.endpointing_sensitivity, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=AWSNovaSonicLLMSettings( - model=model, - voice_id=voice_id, - temperature=params.temperature, - max_tokens=params.max_tokens, - top_p=params.top_p, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - endpointing_sensitivity=params.endpointing_sensitivity, - ), + settings=default_settings, **kwargs, ) self._secret_access_key = secret_access_key @@ -280,12 +308,12 @@ class AWSNovaSonicLLMService(LLMService): self._client: Optional[BedrockRuntimeClient] = None # Audio I/O config (hardware settings, not runtime-tunable) - self._input_sample_rate = params.input_sample_rate - self._input_sample_size = params.input_sample_size - self._input_channel_count = params.input_channel_count - self._output_sample_rate = params.output_sample_rate - self._output_sample_size = params.output_sample_size - self._output_channel_count = params.output_channel_count + self._input_sample_rate = _params.input_sample_rate + self._input_sample_size = _params.input_sample_size + self._input_channel_count = _params.input_channel_count + self._output_sample_rate = _params.output_sample_rate + self._output_sample_size = _params.output_sample_size + self._output_channel_count = _params.output_channel_count self._system_instruction = system_instruction self._tools = tools @@ -295,7 +323,7 @@ class AWSNovaSonicLLMService(LLMService): and not self._is_endpointing_sensitivity_supported() ): logger.warning( - f"endpointing_sensitivity is not supported for model '{model}' and will be ignored. " + f"endpointing_sensitivity is not supported for model '{self._settings.model}' and will be ignored. " "This parameter is only supported starting with Nova 2 Sonic (amazon.nova-2-sonic-v1:0)." ) self._settings.endpointing_sensitivity = None diff --git a/src/pipecat/services/aws/stt.py b/src/pipecat/services/aws/stt.py index 7c3fb398e..1cbfa7329 100644 --- a/src/pipecat/services/aws/stt.py +++ b/src/pipecat/services/aws/stt.py @@ -29,7 +29,7 @@ from pipecat.frames.frames import ( TranscriptionFrame, ) from pipecat.services.aws.utils import build_event_message, decode_event, get_presigned_url -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import AWS_TRANSCRIBE_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -81,8 +81,9 @@ class AWSTranscribeSTTService(WebsocketSTTService): aws_access_key_id: Optional[str] = None, aws_session_token: Optional[str] = None, region: Optional[str] = None, - sample_rate: int = 16000, - language: Language = Language.EN, + sample_rate: Optional[int] = None, + language: Optional[Language] = None, + settings: Optional[AWSTranscribeSTTSettings] = None, ttfs_p99_latency: Optional[float] = AWS_TRANSCRIBE_TTFS_P99, **kwargs, ): @@ -93,29 +94,51 @@ class AWSTranscribeSTTService(WebsocketSTTService): aws_access_key_id: AWS access key ID. If None, uses AWS_ACCESS_KEY_ID environment variable. aws_session_token: AWS session token for temporary credentials. If None, uses AWS_SESSION_TOKEN environment variable. region: AWS region for the service. - sample_rate: Audio sample rate in Hz. Must be 8000 or 16000. Defaults to 16000. - language: Language for transcription. Defaults to English. + sample_rate: Audio sample rate in Hz. Must be 8000 or 16000. + + .. deprecated:: 1.0 + Use ``settings=AWSTranscribeSTTSettings(sample_rate=...)`` instead. + + language: Language for transcription. + + .. deprecated:: 1.0 + Use ``settings=AWSTranscribeSTTSettings(language=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. """ + 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 + + default_settings = AWSTranscribeSTTSettings( + language=self.language_to_service_language(_language) or "en-US", + sample_rate=_sample_rate, + media_encoding="linear16", + number_of_channels=1, + show_speaker_label=False, + enable_channel_identification=False, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( ttfs_p99_latency=ttfs_p99_latency, - settings=AWSTranscribeSTTSettings( - language=self.language_to_service_language(language) or "en-US", - sample_rate=sample_rate, - media_encoding="linear16", - number_of_channels=1, - show_speaker_label=False, - enable_channel_identification=False, - ), + settings=default_settings, **kwargs, ) # Validate sample rate - AWS Transcribe only supports 8000 Hz or 16000 Hz - if sample_rate not in [8000, 16000]: + if _sample_rate not in [8000, 16000]: logger.warning( - f"AWS Transcribe only supports 8000 Hz or 16000 Hz sample rates. Converting from {sample_rate} Hz to 16000 Hz." + f"AWS Transcribe only supports 8000 Hz or 16000 Hz sample rates. Converting from {_sample_rate} Hz to 16000 Hz." ) self._settings.sample_rate = 16000 diff --git a/src/pipecat/services/aws/tts.py b/src/pipecat/services/aws/tts.py index 017477a7a..8e11cb3cd 100644 --- a/src/pipecat/services/aws/tts.py +++ b/src/pipecat/services/aws/tts.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -155,6 +155,9 @@ class AWSPollyTTSService(TTSService): class InputParams(BaseModel): """Input parameters for AWS Polly TTS configuration. + .. deprecated:: 1.0 + Use ``AWSPollyTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: engine: TTS engine to use ('standard', 'neural', etc.). language: Language for synthesis. Defaults to English. @@ -178,9 +181,10 @@ class AWSPollyTTSService(TTSService): aws_access_key_id: Optional[str] = None, aws_session_token: Optional[str] = None, region: Optional[str] = None, - voice_id: str = "Joanna", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[AWSPollyTTSSettings] = None, **kwargs, ): """Initializes the AWS Polly TTS service. @@ -191,26 +195,45 @@ class AWSPollyTTSService(TTSService): aws_session_token: AWS session token for temporary credentials. region: AWS region for Polly service. Defaults to 'us-east-1'. voice_id: Voice ID to use for synthesis. Defaults to 'Joanna'. + + .. deprecated:: 1.0 + Use ``settings=AWSPollyTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses service default. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=AWSPollyTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ - params = params or AWSPollyTTSService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AWSPollyTTSSettings( - model=None, - voice=voice_id, - engine=params.engine, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - volume=params.volume, - lexicon_names=params.lexicon_names, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/azure/image.py b/src/pipecat/services/azure/image.py index 66cc28504..e64e5c7d8 100644 --- a/src/pipecat/services/azure/image.py +++ b/src/pipecat/services/azure/image.py @@ -13,14 +13,14 @@ using REST endpoints for creating images from text prompts. import asyncio import io from dataclasses import dataclass -from typing import AsyncGenerator +from typing import AsyncGenerator, Optional import aiohttp from PIL import Image from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import ImageGenSettings, _warn_deprecated_param @dataclass @@ -46,9 +46,10 @@ class AzureImageGenServiceREST(ImageGenService): image_size: str, api_key: str, endpoint: str, - model: str, + model: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, api_version="2023-06-01-preview", + settings: Optional[AzureImageGenSettings] = None, ): """Initialize the AzureImageGenServiceREST. @@ -57,10 +58,23 @@ class AzureImageGenServiceREST(ImageGenService): api_key: Azure OpenAI API key for authentication. endpoint: Azure OpenAI endpoint URL. model: The image generation model to use. + + .. deprecated:: 1.0 + Use ``settings=AzureImageGenSettings(model=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. api_version: Azure API version string. Defaults to "2023-06-01-preview". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. """ - super().__init__(settings=AzureImageGenSettings(model=model)) + if model is not None: + _warn_deprecated_param("model", "AzureImageGenSettings", "model") + + default_settings = AzureImageGenSettings(model=model) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings) self._api_key = api_key self._azure_endpoint = endpoint diff --git a/src/pipecat/services/azure/llm.py b/src/pipecat/services/azure/llm.py index b1807ad13..b828f0e4e 100644 --- a/src/pipecat/services/azure/llm.py +++ b/src/pipecat/services/azure/llm.py @@ -6,10 +6,14 @@ """Azure OpenAI service implementation for the Pipecat AI framework.""" +from typing import Optional + from loguru import logger from openai import AsyncAzureOpenAI +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class AzureLLMService(OpenAILLMService): @@ -24,8 +28,9 @@ class AzureLLMService(OpenAILLMService): *, api_key: str, endpoint: str, - model: str, + model: Optional[str] = None, api_version: str = "2024-09-01-preview", + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Azure LLM service. @@ -33,15 +38,28 @@ class AzureLLMService(OpenAILLMService): Args: api_key: The API key for accessing Azure OpenAI. endpoint: The Azure endpoint URL. - model: The model identifier to use. + model: The model identifier to use. Defaults to "gpt-4o". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_version: Azure API version. Defaults to "2024-09-01-preview". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "gpt-4o") + if settings is not None: + default_settings.apply_update(settings) + # Initialize variables before calling parent __init__() because that # will call create_client() and we need those values there. self._endpoint = endpoint self._api_version = api_version - super().__init__(api_key=api_key, model=model, **kwargs) + super().__init__(api_key=api_key, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Azure OpenAI endpoint. diff --git a/src/pipecat/services/azure/stt.py b/src/pipecat/services/azure/stt.py index 5533e350e..5ab88c8dd 100644 --- a/src/pipecat/services/azure/stt.py +++ b/src/pipecat/services/azure/stt.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TranscriptionFrame, ) from pipecat.services.azure.common import language_to_azure_language -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import AZURE_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language @@ -79,10 +79,11 @@ class AzureSTTService(STTService): *, api_key: str, region: str, - language: Language = Language.EN_US, + language: Optional[Language] = Language.EN_US, sample_rate: Optional[int] = None, private_endpoint: Optional[str] = None, endpoint_id: Optional[str] = None, + settings: Optional[AzureSTTSettings] = None, ttfs_p99_latency: Optional[float] = AZURE_TTFS_P99, **kwargs, ): @@ -92,30 +93,44 @@ class AzureSTTService(STTService): api_key: Azure Cognitive Services subscription key. region: Azure region for the Speech service (e.g., 'eastus'). language: Language for speech recognition. Defaults to English (US). + + .. deprecated:: 1.0 + Use ``settings=AzureSTTSettings(language=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. private_endpoint: Private endpoint for STT behind firewall. See https://docs.azure.cn/en-us/ai-services/speech-service/speech-services-private-link?tabs=portal endpoint_id: Custom model endpoint id. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService. """ + if language != Language.EN_US: + _warn_deprecated_param("language", "AzureSTTSettings", "language") + + default_settings = AzureSTTSettings( + model=None, + region=region, + language=language_to_azure_language(language) if language else None, + sample_rate=sample_rate, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=AzureSTTSettings( - model=None, - region=region, - language=language_to_azure_language(language), - sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) self._speech_config = SpeechConfig( subscription=api_key, region=region, - speech_recognition_language=language_to_azure_language(language), + speech_recognition_language=default_settings.language + or language_to_azure_language(Language.EN_US), endpoint=private_endpoint, ) diff --git a/src/pipecat/services/azure/tts.py b/src/pipecat/services/azure/tts.py index 6e62c73bf..d37874825 100644 --- a/src/pipecat/services/azure/tts.py +++ b/src/pipecat/services/azure/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.azure.common import language_to_azure_language -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TextAggregationMode, TTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -115,6 +115,9 @@ class AzureBaseTTSService: class InputParams(BaseModel): """Input parameters for Azure TTS voice configuration. + .. deprecated:: 1.0 + Use ``settings=AzureTTSSettings(...)`` instead. + Parameters: emphasis: Emphasis level for speech ("strong", "moderate", "reduced"). language: Language for synthesis. Defaults to English (US). @@ -253,9 +256,10 @@ class AzureTTSService(TTSService, AzureBaseTTSService): *, api_key: str, region: str, - voice: str = "en-US-SaraNeural", + voice: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[AzureBaseTTSService.InputParams] = None, + settings: Optional[AzureTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -265,9 +269,19 @@ class AzureTTSService(TTSService, AzureBaseTTSService): Args: api_key: Azure Cognitive Services subscription key. region: Azure region identifier (e.g., "eastus", "westus2"). - voice: Voice name to use for synthesis. Defaults to "en-US-SaraNeural". + voice: Voice name to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=AzureTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. params: Voice and synthesis parameters configuration. + + .. deprecated:: 1.0 + Use ``settings=AzureTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -276,7 +290,29 @@ class AzureTTSService(TTSService, AzureBaseTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent WordTTSService. """ - params = params or AzureBaseTTSService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -286,25 +322,12 @@ class AzureTTSService(TTSService, AzureBaseTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=AzureTTSSettings( - model=None, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - role=params.role, - style=params.style, - style_degree=params.style_degree, - voice=voice, - volume=params.volume, - ), + settings=default_settings, **kwargs, ) # Initialize Azure-specific functionality from mixin - self._init_azure_base(api_key=api_key, region=region, voice=voice) + self._init_azure_base(api_key=api_key, region=region, voice=default_settings.voice) self._speech_config = None self._speech_synthesizer = None @@ -730,9 +753,10 @@ class AzureHttpTTSService(TTSService, AzureBaseTTSService): *, api_key: str, region: str, - voice: str = "en-US-SaraNeural", + voice: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[AzureBaseTTSService.InputParams] = None, + settings: Optional[AzureTTSSettings] = None, **kwargs, ): """Initialize the Azure HTTP TTS service. @@ -740,34 +764,53 @@ class AzureHttpTTSService(TTSService, AzureBaseTTSService): Args: api_key: Azure Cognitive Services subscription key. region: Azure region identifier (e.g., "eastus", "westus2"). - voice: Voice name to use for synthesis. Defaults to "en-US-SaraNeural". + voice: Voice name to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=AzureTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses service default. params: Voice and synthesis parameters configuration. + + .. deprecated:: 1.0 + Use ``settings=AzureTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or AzureBaseTTSService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=AzureTTSSettings( - model=None, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - pitch=params.pitch, - rate=params.rate, - role=params.role, - style=params.style, - style_degree=params.style_degree, - voice=voice, - volume=params.volume, - ), + settings=default_settings, **kwargs, ) # Initialize Azure-specific functionality from mixin - self._init_azure_base(api_key=api_key, region=region, voice=voice) + self._init_azure_base(api_key=api_key, region=region, voice=default_settings.voice) self._speech_config = None self._speech_synthesizer = None diff --git a/src/pipecat/services/camb/tts.py b/src/pipecat/services/camb/tts.py index 75b299569..4ee2d5171 100644 --- a/src/pipecat/services/camb/tts.py +++ b/src/pipecat/services/camb/tts.py @@ -32,7 +32,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -175,6 +175,9 @@ class CambTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Camb.ai TTS configuration. + .. deprecated:: 1.0 + Use ``settings=CambTTSSettings(...)`` instead. + Parameters: language: Language for synthesis (BCP-47 format). Defaults to English. user_instructions: Custom instructions for mars-instruct model only. @@ -193,47 +196,71 @@ class CambTTSService(TTSService): self, *, api_key: str, - voice_id: int = 147320, - model: str = "mars-flash", + voice_id: Optional[int] = None, + model: Optional[str] = None, timeout: float = 60.0, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[CambTTSSettings] = None, **kwargs, ): """Initialize the Camb.ai TTS service. Args: api_key: Camb.ai API key for authentication. - voice_id: Voice ID to use. Defaults to 147320. + voice_id: Voice ID to use. + + .. deprecated:: 1.0 + Use ``settings=CambTTSSettings(voice=...)`` instead. + model: TTS model to use. Options: "mars-flash" (fast), "mars-pro" (high quality). - Defaults to "mars-flash". + + .. deprecated:: 1.0 + Use ``settings=CambTTSSettings(model=...)`` instead. + timeout: Request timeout in seconds. Defaults to 60.0 (minimum recommended by Camb.ai). sample_rate: Audio sample rate in Hz. If None, uses model-specific default. params: Additional voice parameters. If None, uses defaults. + + .. deprecated:: 1.0 + Use ``settings=CambTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or CambTTSService.InputParams() + 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") + + _params = params or CambTTSService.InputParams() + _model = model or "mars-flash" # Warn if sample rate doesn't match model's supported rate - if sample_rate and sample_rate != MODEL_SAMPLE_RATES.get(model): + if sample_rate and sample_rate != MODEL_SAMPLE_RATES.get(_model): logger.warning( - f"Camb.ai's {model} model only supports {MODEL_SAMPLE_RATES.get(model)}Hz " + f"Camb.ai's {_model} model only supports {MODEL_SAMPLE_RATES.get(_model)}Hz " f"sample rate. Current rate of {sample_rate}Hz may cause issues." ) + 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=CambTTSSettings( - model=model, - voice=voice_id, - language=( - self.language_to_service_language(params.language) - if params.language - else "en-us" - ), - user_instructions=params.user_instructions, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/cartesia/stt.py b/src/pipecat/services/cartesia/stt.py index 526fc9116..530f6a4d1 100644 --- a/src/pipecat/services/cartesia/stt.py +++ b/src/pipecat/services/cartesia/stt.py @@ -158,6 +158,7 @@ class CartesiaSTTService(WebsocketSTTService): base_url: str = "", sample_rate: int = 16000, live_options: Optional[CartesiaLiveOptions] = None, + settings: Optional[CartesiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = CARTESIA_TTFS_P99, **kwargs, ): @@ -168,6 +169,8 @@ class CartesiaSTTService(WebsocketSTTService): base_url: Custom API endpoint URL. If empty, uses default. sample_rate: Audio sample rate in Hz. Defaults to 16000. live_options: Configuration options for transcription service. + settings: Runtime-updatable settings. When provided alongside + ``live_options``, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService. @@ -189,16 +192,20 @@ class CartesiaSTTService(WebsocketSTTService): k: v for k, v in merged_options.items() if not isinstance(v, str) or v != "None" } + default_settings = CartesiaSTTSettings( + model=merged_options["model"], + language=merged_options.get("language"), + encoding=merged_options.get("encoding", "pcm_s16le"), + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=120, keepalive_interval=30, - settings=CartesiaSTTSettings( - model=merged_options["model"], - language=merged_options.get("language"), - encoding=merged_options.get("encoding", "pcm_s16le"), - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/cartesia/tts.py b/src/pipecat/services/cartesia/tts.py index 2e637c339..2f6178b91 100644 --- a/src/pipecat/services/cartesia/tts.py +++ b/src/pipecat/services/cartesia/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.text.base_text_aggregator import BaseTextAggregator @@ -263,14 +263,15 @@ class CartesiaTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, cartesia_version: str = "2025-04-16", url: str = "wss://api.cartesia.ai/tts/websocket", - model: str = "sonic-3", + model: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[CartesiaTTSSettings] = None, text_aggregator: Optional[BaseTextAggregator] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, @@ -281,13 +282,27 @@ class CartesiaTTSService(AudioContextTTSService): Args: api_key: Cartesia API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(voice=...)`` instead. + cartesia_version: API version string for Cartesia service. url: WebSocket URL for Cartesia TTS API. model: TTS model to use (e.g., "sonic-3"). + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate. If None, uses default. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregator: Custom text aggregator for processing input text. .. deprecated:: 0.0.95 @@ -301,6 +316,13 @@ 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 @@ -314,7 +336,24 @@ 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() + _params = params or CartesiaTTSService.InputParams() + + default_settings = CartesiaTTSSettings( + model=model or "sonic-3", + voice=voice_id, + output_container=container, + output_encoding=encoding, + output_sample_rate=0, + language=( + self.language_to_service_language(_params.language) if _params.language else None + ), + speed=_params.speed, + emotion=_params.emotion, + generation_config=_params.generation_config, + pronunciation_dict_id=_params.pronunciation_dict_id, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -324,20 +363,7 @@ class CartesiaTTSService(AudioContextTTSService): supports_word_timestamps=True, sample_rate=sample_rate, text_aggregator=text_aggregator, - settings=CartesiaTTSSettings( - model=model, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - speed=params.speed, - emotion=params.emotion, - generation_config=params.generation_config, - pronunciation_dict_id=params.pronunciation_dict_id, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -717,14 +743,15 @@ class CartesiaHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, - model: str = "sonic-3", + voice_id: Optional[str] = None, + model: Optional[str] = None, base_url: str = "https://api.cartesia.ai", cartesia_version: str = "2024-11-13", sample_rate: Optional[int] = None, encoding: str = "pcm_s16le", container: str = "raw", params: Optional[InputParams] = None, + settings: Optional[CartesiaTTSSettings] = None, **kwargs, ): """Initialize the Cartesia HTTP TTS service. @@ -732,33 +759,58 @@ class CartesiaHttpTTSService(TTSService): Args: api_key: Cartesia API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(voice=...)`` instead. + model: TTS model to use (e.g., "sonic-3"). + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(model=...)`` instead. + base_url: Base URL for Cartesia HTTP API. cartesia_version: API version string for Cartesia service. sample_rate: Audio sample rate. If None, uses default. encoding: Audio encoding format. container: Audio container format. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=CartesiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ - params = params or CartesiaHttpTTSService.InputParams() + 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() + + default_settings = CartesiaTTSSettings( + model=model or "sonic-3", + voice=voice_id, + output_container=container, + output_encoding=encoding, + output_sample_rate=0, + language=( + self.language_to_service_language(_params.language) if _params.language else None + ), + speed=_params.speed, + emotion=_params.emotion, + generation_config=_params.generation_config, + pronunciation_dict_id=_params.pronunciation_dict_id, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=CartesiaTTSSettings( - model=model, - voice=voice_id, - output_container=container, - output_encoding=encoding, - output_sample_rate=0, - language=self.language_to_service_language(params.language) - if params.language - else None, - speed=params.speed, - emotion=params.emotion, - generation_config=params.generation_config, - pronunciation_dict_id=params.pronunciation_dict_id, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/cerebras/llm.py b/src/pipecat/services/cerebras/llm.py index e1ecceef7..ec3c3f09b 100644 --- a/src/pipecat/services/cerebras/llm.py +++ b/src/pipecat/services/cerebras/llm.py @@ -6,10 +6,14 @@ """Cerebras LLM service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class CerebrasLLMService(OpenAILLMService): @@ -24,7 +28,8 @@ class CerebrasLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.cerebras.ai/v1", - model: str = "gpt-oss-120b", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Cerebras LLM service. @@ -33,9 +38,22 @@ class CerebrasLLMService(OpenAILLMService): api_key: The API key for accessing Cerebras's API. base_url: The base URL for Cerebras API. Defaults to "https://api.cerebras.ai/v1". model: The model identifier to use. Defaults to "gpt-oss-120b". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "gpt-oss-120b") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Cerebras API endpoint. diff --git a/src/pipecat/services/deepgram/flux/stt.py b/src/pipecat/services/deepgram/flux/stt.py index 984906c6c..fdfd65613 100644 --- a/src/pipecat/services/deepgram/flux/stt.py +++ b/src/pipecat/services/deepgram/flux/stt.py @@ -28,7 +28,7 @@ from pipecat.frames.frames import ( UserStartedSpeakingFrame, UserStoppedSpeakingFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 @@ -124,8 +124,8 @@ class DeepgramFluxSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for Deepgram Flux API. - This class defines all available connection parameters for the Deepgram Flux API - based on the official documentation. + .. deprecated:: 1.0 + Use ``settings=DeepgramFluxSTTSettings(...)`` instead. Parameters: eager_eot_threshold: Optional. EagerEndOfTurn/TurnResumed are off by default. @@ -158,10 +158,11 @@ class DeepgramFluxSTTService(WebsocketSTTService): api_key: str, url: str = "wss://api.deepgram.com/v2/listen", sample_rate: Optional[int] = None, - model: str = "flux-general-en", + model: Optional[str] = None, flux_encoding: str = "linear16", params: Optional[InputParams] = None, should_interrupt: bool = True, + settings: Optional[DeepgramFluxSTTSettings] = None, **kwargs, ): """Initialize the Deepgram Flux STT service. @@ -170,12 +171,21 @@ class DeepgramFluxSTTService(WebsocketSTTService): api_key: Deepgram API key for authentication. Required for API access. url: WebSocket URL for the Deepgram Flux API. Defaults to the preview endpoint. sample_rate: Audio sample rate in Hz. If None, uses the rate from params or 16000. - model: Deepgram Flux model to use for transcription. Currently only supports "flux-general-en". + model: Deepgram Flux model to use for transcription. + + .. deprecated:: 1.0 + Use ``settings=DeepgramFluxSTTSettings(model=...)`` instead. + flux_encoding: Audio encoding format required by Flux API. Must be "linear16". Raw signed little-endian 16-bit PCM encoding. params: InputParams instance containing detailed API configuration options. - If None, default parameters will be used. + + .. deprecated:: 1.0 + Use ``settings=DeepgramFluxSTTSettings(...)`` instead. + should_interrupt: Determine whether the bot should be interrupted when Flux detects that the user is speaking. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent WebsocketSTTService class. Examples: @@ -185,18 +195,21 @@ class DeepgramFluxSTTService(WebsocketSTTService): Advanced usage with custom parameters:: - params = DeepgramFluxSTTService.InputParams( - eager_eot_threshold=0.5, - eot_threshold=0.8, - keyterm=["AI", "machine learning", "neural network"], - tag=["production", "voice-agent"] - ) stt = DeepgramFluxSTTService( api_key="your-api-key", - model="flux-general-en", - params=params + settings=DeepgramFluxSTTSettings( + model="flux-general-en", + eager_eot_threshold=0.5, + eot_threshold=0.8, + keyterm=["AI", "machine learning", "neural network"], + tag=["production", "voice-agent"], + ), ) """ + 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 @@ -207,22 +220,27 @@ 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() + _params = params or DeepgramFluxSTTService.InputParams() + + default_settings = DeepgramFluxSTTSettings( + model=model or "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, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, reconnect_on_error=False, - settings=DeepgramFluxSTTSettings( - model=model, - language=Language.EN, - encoding=flux_encoding, - eager_eot_threshold=params.eager_eot_threshold, - eot_threshold=params.eot_threshold, - eot_timeout_ms=params.eot_timeout_ms, - keyterm=params.keyterm or [], - mip_opt_out=params.mip_opt_out, - tag=params.tag or [], - min_confidence=params.min_confidence, - ), + settings=default_settings, **kwargs, ) self._api_key = api_key diff --git a/src/pipecat/services/deepgram/sagemaker/stt.py b/src/pipecat/services/deepgram/sagemaker/stt.py index 24a25e5fd..6d813157d 100644 --- a/src/pipecat/services/deepgram/sagemaker/stt.py +++ b/src/pipecat/services/deepgram/sagemaker/stt.py @@ -41,7 +41,7 @@ from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_stt try: - from pipecat.services.deepgram.stt import LiveOptions + from deepgram import LiveOptions except ModuleNotFoundError as e: logger.error(f"Exception: {e}") logger.error( @@ -51,10 +51,10 @@ except ModuleNotFoundError as e: @dataclass -class DeepgramSageMakerSTTSettings(DeepgramSTTSettings): +class DeepgramSageMakerSTTSettings(_DeepgramSTTSettingsBase): """Settings for the Deepgram SageMaker STT service. - See ``DeepgramSTTSettings`` for full documentation. + See ``_DeepgramSTTSettingsBase`` for full documentation. """ pass @@ -97,6 +97,7 @@ class DeepgramSageMakerSTTService(STTService): region: str, sample_rate: Optional[int] = None, live_options: Optional[LiveOptions] = None, + settings: Optional[DeepgramSageMakerSTTSettings] = None, ttfs_p99_latency: Optional[float] = DEEPGRAM_SAGEMAKER_TTFS_P99, **kwargs, ): @@ -111,37 +112,38 @@ class DeepgramSageMakerSTTService(STTService): live_options: Deepgram LiveOptions configuration. Treated as a delta from a set of sensible defaults — only the fields you set are overridden; all others keep their default values. + settings: Runtime-updatable settings. When provided alongside + ``live_options``, ``settings`` values take precedence (applied + after the ``live_options`` merge). ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the parent STTService. """ sample_rate = sample_rate or (live_options.sample_rate if live_options else None) - settings = DeepgramSageMakerSTTSettings( - model="nova-3", - language=Language.EN, + default_options = LiveOptions( encoding="linear16", + language=Language.EN, + model="nova-3", channels=1, interim_results=True, - smart_format=False, punctuate=True, - profanity_filter=True, - vad_events=False, - diarize=False, - endpointing=None, ) + default_settings = DeepgramSageMakerSTTSettings( + model=default_options.model, + language=default_options.language, + live_options=default_options, + ) if live_options: - lo_dict = live_options.to_dict() - delta = DeepgramSageMakerSTTSettings.from_mapping( - {k: v for k, v in lo_dict.items() if k != "sample_rate"} - ) - settings.apply_update(delta) + default_settings._merge_live_options_delta(live_options) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) @@ -228,8 +230,9 @@ class DeepgramSageMakerSTTService(STTService): """ logger.debug("Connecting to Deepgram on SageMaker...") - # Reconstruct a LiveOptions from the flat settings to build the query string. - live_options = LiveOptions(**self._settings.given_fields()) + live_options = LiveOptions( + **{**self._settings.live_options.to_dict(), "sample_rate": self.sample_rate} + ) # Build query string from live_options, converting booleans to strings query_params = {} @@ -240,7 +243,6 @@ class DeepgramSageMakerSTTService(STTService): query_params[key] = str(value).lower() else: query_params[key] = str(value) - query_params["sample_rate"] = str(self.sample_rate) query_string = "&".join(f"{k}={v}" for k, v in query_params.items()) diff --git a/src/pipecat/services/deepgram/sagemaker/tts.py b/src/pipecat/services/deepgram/sagemaker/tts.py index b583ce76c..0c141bac0 100644 --- a/src/pipecat/services/deepgram/sagemaker/tts.py +++ b/src/pipecat/services/deepgram/sagemaker/tts.py @@ -33,7 +33,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.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -78,9 +78,10 @@ class DeepgramSageMakerTTSService(TTSService): *, endpoint_name: str, region: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramSageMakerTTSSettings] = None, **kwargs, ): """Initialize the Deepgram SageMaker TTS service. @@ -90,21 +91,36 @@ class DeepgramSageMakerTTSService(TTSService): deployed (e.g., "my-deepgram-tts-endpoint"). region: AWS region where the endpoint is deployed (e.g., "us-east-2"). voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + + .. deprecated:: 1.0 + Use ``settings=DeepgramSageMakerTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses the value from StartFrame. encoding: Audio encoding format. Defaults to "linear16". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ + if voice is not None: + _warn_deprecated_param("voice", "DeepgramSageMakerTTSSettings", "voice") + + voice = voice or "aura-2-helena-en" + + default_settings = DeepgramSageMakerTTSSettings( + model=voice, + voice=voice, + language=None, + encoding=encoding, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, push_stop_frames=True, pause_frame_processing=True, append_trailing_space=True, - settings=DeepgramSageMakerTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/deepgram/stt.py b/src/pipecat/services/deepgram/stt.py index 343a87e2a..fe3add7cf 100644 --- a/src/pipecat/services/deepgram/stt.py +++ b/src/pipecat/services/deepgram/stt.py @@ -256,6 +256,7 @@ class DeepgramSTTService(STTService): live_options: Optional[LiveOptions] = None, addons: Optional[Dict] = None, should_interrupt: bool = True, + settings: Optional[DeepgramSTTSettings] = None, ttfs_p99_latency: Optional[float] = DEEPGRAM_TTFS_P99, **kwargs, ): @@ -279,6 +280,9 @@ class DeepgramSTTService(STTService): .. deprecated:: 0.0.99 This parameter will be removed along with `vad_events` support. + settings: Runtime-updatable settings. When provided alongside + ``live_options``, ``settings`` values take precedence (applied + after the ``live_options`` merge). ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the parent STTService. @@ -299,7 +303,7 @@ class DeepgramSTTService(STTService): ) base_url = url - settings = DeepgramSTTSettings( + default_settings = DeepgramSTTSettings( model="nova-3-general", language=Language.EN, encoding="linear16", @@ -318,15 +322,18 @@ class DeepgramSTTService(STTService): delta = DeepgramSTTSettings.from_mapping( {k: v for k, v in lo_dict.items() if k != "sample_rate"} ) - settings.apply_update(delta) + default_settings.apply_update(delta) + + if settings is not None: + default_settings.apply_update(settings) # Sync extra to top-level fields so self._settings is unambiguous - settings._sync_extra_to_fields() + default_settings._sync_extra_to_fields() super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/deepgram/tts.py b/src/pipecat/services/deepgram/tts.py index c05b90868..4524d17b6 100644 --- a/src/pipecat/services/deepgram/tts.py +++ b/src/pipecat/services/deepgram/tts.py @@ -30,7 +30,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService, WebsocketTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -72,41 +72,55 @@ class DeepgramTTSService(WebsocketTTSService): self, *, api_key: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, base_url: str = "wss://api.deepgram.com", sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramTTSSettings] = None, **kwargs, ): """Initialize the Deepgram WebSocket TTS service. Args: api_key: Deepgram API key for authentication. - voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + voice: Voice model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=DeepgramTTSSettings(voice=...)`` instead. + base_url: WebSocket base URL for Deepgram API. Defaults to "wss://api.deepgram.com". sample_rate: Audio sample rate in Hz. If None, uses service default. encoding: Audio encoding format. Defaults to "linear16". Must be one of SUPPORTED_ENCODINGS. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent InterruptibleTTSService class. Raises: 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." ) + default_settings = DeepgramTTSSettings( + model=voice or "aura-2-helena-en", + voice=voice or "aura-2-helena-en", + language=None, + encoding=encoding, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, pause_frame_processing=True, push_stop_frames=True, append_trailing_space=True, - settings=DeepgramTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) @@ -375,32 +389,46 @@ class DeepgramHttpTTSService(TTSService): self, *, api_key: str, - voice: str = "aura-2-helena-en", + voice: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, base_url: str = "https://api.deepgram.com", sample_rate: Optional[int] = None, encoding: str = "linear16", + settings: Optional[DeepgramTTSSettings] = None, **kwargs, ): """Initialize the Deepgram TTS service. Args: api_key: Deepgram API key for authentication. - voice: Voice model to use for synthesis. Defaults to "aura-2-helena-en". + voice: Voice model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=DeepgramTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests with connection pooling. base_url: Custom base URL for Deepgram API. Defaults to "https://api.deepgram.com". sample_rate: Audio sample rate in Hz. If None, uses service default. encoding: Audio encoding format. Defaults to "linear16". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ + if voice is not None: + _warn_deprecated_param("voice", "DeepgramTTSSettings", "voice") + + default_settings = DeepgramTTSSettings( + model=voice or "aura-2-helena-en", + voice=voice or "aura-2-helena-en", + language=None, + encoding=encoding, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, - settings=DeepgramTTSSettings( - model=voice, - voice=voice, - language=None, - encoding=encoding, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/deepseek/llm.py b/src/pipecat/services/deepseek/llm.py index 70318c9ba..2ebc2e6eb 100644 --- a/src/pipecat/services/deepseek/llm.py +++ b/src/pipecat/services/deepseek/llm.py @@ -6,10 +6,14 @@ """DeepSeek LLM service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class DeepSeekLLMService(OpenAILLMService): @@ -24,7 +28,8 @@ class DeepSeekLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.deepseek.com/v1", - model: str = "deepseek-chat", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the DeepSeek LLM service. @@ -33,9 +38,22 @@ class DeepSeekLLMService(OpenAILLMService): api_key: The API key for accessing DeepSeek's API. base_url: The base URL for DeepSeek API. Defaults to "https://api.deepseek.com/v1". model: The model identifier to use. Defaults to "deepseek-chat". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "deepseek-chat") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for DeepSeek API endpoint. diff --git a/src/pipecat/services/elevenlabs/stt.py b/src/pipecat/services/elevenlabs/stt.py index 0cf13121e..d5897b5c5 100644 --- a/src/pipecat/services/elevenlabs/stt.py +++ b/src/pipecat/services/elevenlabs/stt.py @@ -35,7 +35,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import ELEVENLABS_REALTIME_TTFS_P99, ELEVENLABS_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService, WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -228,6 +228,9 @@ class ElevenLabsSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for ElevenLabs STT API. + .. deprecated:: 1.0 + Use ``settings=ElevenLabsSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. tag_audio_events: Whether to include audio events like (laughter), (coughing), in the transcription. @@ -242,9 +245,10 @@ class ElevenLabsSTTService(SegmentedSTTService): api_key: str, aiohttp_session: aiohttp.ClientSession, base_url: str = "https://api.elevenlabs.io", - model: str = "scribe_v2", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsSTTSettings] = None, ttfs_p99_latency: Optional[float] = ELEVENLABS_TTFS_P99, **kwargs, ): @@ -254,25 +258,44 @@ class ElevenLabsSTTService(SegmentedSTTService): api_key: ElevenLabs API key for authentication. aiohttp_session: aiohttp ClientSession for HTTP requests. base_url: Base URL for ElevenLabs API. - model: Model ID for transcription. Defaults to "scribe_v2". + model: Model ID for transcription. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsSTTSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the STT service. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - params = params or ElevenLabsSTTService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=ElevenLabsSTTSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "eng", - tag_audio_events=params.tag_audio_events, - ), + settings=default_settings, **kwargs, ) @@ -429,6 +452,9 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for ElevenLabs Realtime STT API. + .. deprecated:: 1.0 + Use ``settings=ElevenLabsRealtimeSTTSettings(...)`` instead. + Parameters: language_code: ISO-639-1 or ISO-639-3 language code. Leave None for auto-detection. commit_strategy: How to segment speech - manual (Pipecat VAD) or vad (ElevenLabs VAD). @@ -460,9 +486,10 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): *, api_key: str, base_url: str = "api.elevenlabs.io", - model: str = "scribe_v2_realtime", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsRealtimeSTTSettings] = None, ttfs_p99_latency: Optional[float] = ELEVENLABS_REALTIME_TTFS_P99, **kwargs, ): @@ -471,32 +498,51 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService): Args: api_key: ElevenLabs API key for authentication. base_url: Base URL for ElevenLabs WebSocket API. - model: Model ID for transcription. Defaults to "scribe_v2_realtime". + model: Model ID for transcription. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsRealtimeSTTSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the STT service. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsRealtimeSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to WebsocketSTTService. """ - params = params or ElevenLabsRealtimeSTTService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=10, keepalive_interval=5, - settings=ElevenLabsRealtimeSTTSettings( - model=model, - language=params.language_code, - commit_strategy=params.commit_strategy, - vad_silence_threshold_secs=params.vad_silence_threshold_secs, - vad_threshold=params.vad_threshold, - min_speech_duration_ms=params.min_speech_duration_ms, - min_silence_duration_ms=params.min_silence_duration_ms, - include_timestamps=params.include_timestamps, - enable_logging=params.enable_logging, - include_language_detection=params.include_language_detection, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/elevenlabs/tts.py b/src/pipecat/services/elevenlabs/tts.py index 1811ed971..b98ce6e1b 100644 --- a/src/pipecat/services/elevenlabs/tts.py +++ b/src/pipecat/services/elevenlabs/tts.py @@ -44,7 +44,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import ( AudioContextTTSService, TextAggregationMode, @@ -331,6 +331,9 @@ class ElevenLabsTTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for ElevenLabs TTS configuration. + .. deprecated:: 1.0 + Use ``settings=ElevenLabsTTSSettings(...)`` instead. + Parameters: language: Language to use for synthesis. stability: Voice stability control (0.0 to 1.0). @@ -361,11 +364,13 @@ class ElevenLabsTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, - model: str = "eleven_turbo_v2_5", + voice_id: Optional[str] = None, + model: Optional[str] = None, url: str = "wss://api.elevenlabs.io", sample_rate: Optional[int] = None, + pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsTTSSettings] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, **kwargs, @@ -375,10 +380,26 @@ class ElevenLabsTTSService(AudioContextTTSService): Args: api_key: ElevenLabs API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsTTSSettings(voice=...)`` instead. + model: TTS model to use (e.g., "eleven_turbo_v2_5"). + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsTTSSettings(model=...)`` instead. + url: WebSocket URL for ElevenLabs TTS API. sample_rate: Audio sample rate. If None, uses default. + pronunciation_dictionary_locators: List of pronunciation dictionary + locators to use. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregation_mode: How to aggregate incoming text before synthesis. aggregate_sentences: Whether to aggregate sentences within the TTSService. @@ -387,6 +408,13 @@ 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 @@ -403,7 +431,26 @@ 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() + _params = params or ElevenLabsTTSService.InputParams() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -413,22 +460,7 @@ class ElevenLabsTTSService(AudioContextTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=ElevenLabsTTSSettings( - model=model, - voice=voice_id, - language=( - self.language_to_service_language(params.language) if params.language else None - ), - stability=params.stability, - similarity_boost=params.similarity_boost, - style=params.style, - use_speaker_boost=params.use_speaker_boost, - speed=params.speed, - auto_mode=str(params.auto_mode).lower(), - enable_ssml_parsing=params.enable_ssml_parsing, - enable_logging=params.enable_logging, - apply_text_normalization=params.apply_text_normalization, - ), + settings=default_settings, **kwargs, ) @@ -437,7 +469,11 @@ class ElevenLabsTTSService(AudioContextTTSService): self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + self._pronunciation_dictionary_locators = ( + pronunciation_dictionary_locators + if pronunciation_dictionary_locators is not None + else _params.pronunciation_dictionary_locators + ) self._cumulative_time = 0 # Track partial words that span across alignment chunks @@ -871,6 +907,9 @@ class ElevenLabsHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for ElevenLabs HTTP TTS configuration. + .. deprecated:: 1.0 + Use ``settings=ElevenLabsHttpTTSSettings(...)`` instead. + Parameters: language: Language to use for synthesis. optimize_streaming_latency: Latency optimization level (0-4). @@ -897,12 +936,14 @@ class ElevenLabsHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "eleven_turbo_v2_5", + model: Optional[str] = None, base_url: str = "https://api.elevenlabs.io", sample_rate: Optional[int] = None, + pronunciation_dictionary_locators: Optional[List[PronunciationDictionaryLocator]] = None, params: Optional[InputParams] = None, + settings: Optional[ElevenLabsHttpTTSSettings] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, **kwargs, @@ -912,11 +953,27 @@ class ElevenLabsHttpTTSService(TTSService): Args: api_key: ElevenLabs API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsHttpTTSSettings(voice=...)`` instead. + aiohttp_session: aiohttp ClientSession for HTTP requests. model: TTS model to use (e.g., "eleven_turbo_v2_5"). + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsHttpTTSSettings(model=...)`` instead. + base_url: Base URL for ElevenLabs HTTP API. sample_rate: Audio sample rate. If None, uses default. + pronunciation_dictionary_locators: List of pronunciation dictionary + locators to use. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=ElevenLabsHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregation_mode: How to aggregate incoming text before synthesis. aggregate_sentences: Whether to aggregate sentences within the TTSService. @@ -925,7 +982,31 @@ class ElevenLabsHttpTTSService(TTSService): **kwargs: Additional arguments passed to the parent service. """ - params = params or ElevenLabsHttpTTSService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -934,20 +1015,7 @@ class ElevenLabsHttpTTSService(TTSService): push_stop_frames=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=ElevenLabsHttpTTSSettings( - model=model, - voice=voice_id, - language=self.language_to_service_language(params.language) - if params.language - else None, - optimize_streaming_latency=params.optimize_streaming_latency, - stability=params.stability, - similarity_boost=params.similarity_boost, - style=params.style, - use_speaker_boost=params.use_speaker_boost, - speed=params.speed, - apply_text_normalization=params.apply_text_normalization, - ), + settings=default_settings, **kwargs, ) @@ -957,7 +1025,11 @@ class ElevenLabsHttpTTSService(TTSService): self._output_format = "" # initialized in start() self._voice_settings = self._set_voice_settings() - self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators + self._pronunciation_dictionary_locators = ( + pronunciation_dictionary_locators + if pronunciation_dictionary_locators is not None + else _params.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 c16d31b43..b301ad4e6 100644 --- a/src/pipecat/services/fal/image.py +++ b/src/pipecat/services/fal/image.py @@ -23,7 +23,7 @@ from pydantic import BaseModel from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import ImageGenSettings, _warn_deprecated_param try: import fal_client @@ -75,8 +75,9 @@ class FalImageGenService(ImageGenService): *, params: InputParams, aiohttp_session: aiohttp.ClientSession, - model: str = "fal-ai/fast-sdxl", + model: Optional[str] = None, key: Optional[str] = None, + settings: Optional[FalImageGenSettings] = None, **kwargs, ): """Initialize the FalImageGenService. @@ -85,10 +86,23 @@ class FalImageGenService(ImageGenService): params: Input parameters for image generation configuration. aiohttp_session: HTTP client session for downloading generated images. model: The Fal.ai model to use for generation. Defaults to "fal-ai/fast-sdxl". + + .. deprecated:: 1.0 + Use ``settings=FalImageGenSettings(model=...)`` instead. + key: Optional API key for Fal.ai. If provided, sets FAL_KEY environment variable. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent ImageGenService. """ - super().__init__(settings=FalImageGenSettings(model=model), **kwargs) + if model is not None: + _warn_deprecated_param("model", "FalImageGenSettings", "model") + + default_settings = FalImageGenSettings(model=model or "fal-ai/fast-sdxl") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._params = params self._aiohttp_session = aiohttp_session if key: diff --git a/src/pipecat/services/fal/stt.py b/src/pipecat/services/fal/stt.py index bf70c1c2a..76e9d46ae 100644 --- a/src/pipecat/services/fal/stt.py +++ b/src/pipecat/services/fal/stt.py @@ -18,7 +18,7 @@ from loguru import logger from pydantic import BaseModel from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import FAL_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -176,6 +176,9 @@ class FalSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for Fal's Wizper API. + .. deprecated:: 1.0 + Use ``settings=FalSTTSettings(...)`` instead. + Parameters: language: Language of the audio input. Defaults to English. task: Task to perform ('transcribe' or 'translate'). Defaults to 'transcribe'. @@ -194,6 +197,7 @@ class FalSTTService(SegmentedSTTService): api_key: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[FalSTTSettings] = None, ttfs_p99_latency: Optional[float] = FAL_TTFS_P99, **kwargs, ): @@ -203,24 +207,37 @@ class FalSTTService(SegmentedSTTService): api_key: Fal API key. If not provided, will check FAL_KEY environment variable. sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate. params: Configuration parameters for the Wizper API. + + .. deprecated:: 1.0 + Use ``settings=FalSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ - params = params or FalSTTService.InputParams() + if params is not None: + _warn_deprecated_param("params", "FalSTTSettings") + + _params = params or FalSTTService.InputParams() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=FalSTTSettings( - model=None, - language=self.language_to_service_language(params.language) - if params.language - else "en", - task=params.task, - chunk_level=params.chunk_level, - version=params.version, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/fireworks/llm.py b/src/pipecat/services/fireworks/llm.py index 92deb00b9..9fa9e44bd 100644 --- a/src/pipecat/services/fireworks/llm.py +++ b/src/pipecat/services/fireworks/llm.py @@ -6,10 +6,14 @@ """Fireworks AI service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class FireworksLLMService(OpenAILLMService): @@ -23,8 +27,9 @@ class FireworksLLMService(OpenAILLMService): self, *, api_key: str, - model: str = "accounts/fireworks/models/firefunction-v2", + model: Optional[str] = None, base_url: str = "https://api.fireworks.ai/inference/v1", + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Fireworks LLM service. @@ -32,10 +37,25 @@ class FireworksLLMService(OpenAILLMService): Args: api_key: The API key for accessing Fireworks AI. model: The model identifier to use. Defaults to "accounts/fireworks/models/firefunction-v2". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for Fireworks API. Defaults to "https://api.fireworks.ai/inference/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings( + model=model or "accounts/fireworks/models/firefunction-v2" + ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Fireworks API endpoint. diff --git a/src/pipecat/services/fish/tts.py b/src/pipecat/services/fish/tts.py index 9f9d753de..e95cceebd 100644 --- a/src/pipecat/services/fish/tts.py +++ b/src/pipecat/services/fish/tts.py @@ -29,7 +29,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -95,6 +95,9 @@ class FishAudioTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Input parameters for Fish Audio TTS configuration. + .. deprecated:: 1.0 + Use ``settings=FishAudioTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. latency: Latency mode ("normal" or "balanced"). Defaults to "normal". @@ -115,10 +118,11 @@ class FishAudioTTSService(InterruptibleTTSService): api_key: str, reference_id: Optional[str] = None, # This is the voice ID model: Optional[str] = None, # Deprecated - model_id: str = "s1", + model_id: Optional[str] = None, output_format: FishAudioOutputFormat = "pcm", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[FishAudioTTSSettings] = None, **kwargs, ): """Initialize the Fish Audio TTS service. @@ -126,19 +130,40 @@ class FishAudioTTSService(InterruptibleTTSService): Args: api_key: Fish Audio API key for authentication. reference_id: Reference ID of the voice model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=FishAudioTTSSettings(voice=...)`` instead. + model: Deprecated. Reference ID of the voice model to use for synthesis. - .. deprecated:: 0.0.74 - The `model` parameter is deprecated and will be removed in version 0.1.0. - Use `reference_id` instead to specify the voice model. + .. deprecated:: 0.0.74 + The ``model`` parameter is deprecated and will be removed in version 0.1.0. + Use ``reference_id`` instead to specify the voice model. + + model_id: Specify which Fish Audio TTS model to use (e.g. "s1"). + + .. deprecated:: 1.0 + Use ``settings=FishAudioTTSSettings(model=...)`` instead. - model_id: Specify which Fish Audio TTS model to use (e.g. "s1") output_format: Audio output format. Defaults to "pcm". sample_rate: Audio sample rate. If None, uses default. params: Additional input parameters for voice customization. + + .. deprecated:: 1.0 + Use ``settings=FishAudioTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ - params = params or FishAudioTTSService.InputParams() + 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: @@ -146,9 +171,6 @@ class FishAudioTTSService(InterruptibleTTSService): "Cannot specify both 'model' and 'reference_id'. Use 'reference_id' only." ) - if model is None and reference_id is None: - raise ValueError("Must specify 'reference_id' (or deprecated 'model') parameter.") - if model: import warnings @@ -162,21 +184,25 @@ class FishAudioTTSService(InterruptibleTTSService): ) reference_id = model + default_settings = FishAudioTTSSettings( + model=model_id or "s1", + voice=reference_id, + fish_sample_rate=0, + latency=_params.latency, + format=output_format, + normalize=_params.normalize, + prosody_speed=_params.prosody_speed, + prosody_volume=_params.prosody_volume, + reference_id=reference_id, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( push_stop_frames=True, pause_frame_processing=True, sample_rate=sample_rate, - settings=FishAudioTTSSettings( - model=model_id, - voice=reference_id, - fish_sample_rate=0, - latency=params.latency, - format=output_format, - normalize=params.normalize, - prosody_speed=params.prosody_speed, - prosody_volume=params.prosody_volume, - reference_id=reference_id, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/gladia/stt.py b/src/pipecat/services/gladia/stt.py index bba554b4a..f2376d93e 100644 --- a/src/pipecat/services/gladia/stt.py +++ b/src/pipecat/services/gladia/stt.py @@ -39,7 +39,7 @@ from pipecat.services.gladia.config import ( PreProcessingConfig, RealtimeProcessingConfig, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import GLADIA_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -249,10 +249,11 @@ class GladiaSTTService(WebsocketSTTService): url: str = "https://api.gladia.io/v2/live", confidence: Optional[float] = None, sample_rate: Optional[int] = None, - model: str = "solaria-1", + model: Optional[str] = None, params: Optional[GladiaInputParams] = None, max_buffer_size: int = 1024 * 1024 * 20, # 20MB default buffer should_interrupt: bool = True, + settings: Optional[GladiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = GLADIA_TTFS_P99, **kwargs, ): @@ -269,15 +270,30 @@ class GladiaSTTService(WebsocketSTTService): No confidence threshold is applied. sample_rate: Audio sample rate in Hz. If None, uses service default. - model: Model to use for transcription. Defaults to "solaria-1". + model: Model to use for transcription. + + .. deprecated:: 1.0 + Use ``settings=GladiaSTTSettings(model=...)`` instead. + params: Additional configuration parameters for Gladia service. + + .. deprecated:: 1.0 + Use ``settings=GladiaSTTSettings(...)`` instead. + max_buffer_size: Maximum size of audio buffer in bytes. Defaults to 20MB. should_interrupt: Determine whether the bot should be interrupted when Gladia VAD detects user speech. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService parent class. """ + 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: @@ -307,26 +323,30 @@ class GladiaSTTService(WebsocketSTTService): if language_code: language_config = LanguageConfig(languages=[language_code], code_switching=False) + default_settings = GladiaSTTSettings( + model=model or "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, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=20, keepalive_interval=5, - settings=GladiaSTTSettings( - model=model, - language=None, - encoding=params.encoding, - bit_depth=params.bit_depth, - channels=params.channels, - custom_metadata=params.custom_metadata, - endpointing=params.endpointing, - maximum_duration_without_endpointing=params.maximum_duration_without_endpointing, - language_config=language_config, - pre_processing=params.pre_processing, - realtime_processing=params.realtime_processing, - messages_config=params.messages_config, - enable_vad=params.enable_vad, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/google/gemini_live/llm.py b/src/pipecat/services/google/gemini_live/llm.py index 2ed11c739..518684dfb 100644 --- a/src/pipecat/services/google/gemini_live/llm.py +++ b/src/pipecat/services/google/gemini_live/llm.py @@ -76,7 +76,7 @@ from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAIUserContextAggregator, ) -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.string import match_endofsentence from pipecat.utils.time import time_now_iso8601 @@ -552,6 +552,9 @@ class ContextWindowCompressionParams(BaseModel): class InputParams(BaseModel): """Input parameters for Gemini Live generation. + .. deprecated:: + Use ``GeminiLiveLLMSettings`` instead. + Parameters: frequency_penalty: Frequency penalty for generation (0.0-2.0). Defaults to None. max_tokens: Maximum tokens to generate. Must be >= 1. Defaults to 4096. @@ -647,13 +650,14 @@ class GeminiLiveLLMService(LLMService): *, api_key: str, base_url: Optional[str] = None, - model="models/gemini-2.5-flash-native-audio-preview-12-2025", + model: Optional[str] = None, voice_id: str = "Charon", start_audio_paused: bool = False, start_video_paused: bool = False, system_instruction: Optional[str] = None, tools: Optional[Union[List[dict], ToolsSchema]] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiLiveLLMSettings] = None, inference_on_context_initialization: bool = True, file_api_base_url: str = "https://generativelanguage.googleapis.com/v1beta/files", http_options: Optional[HttpOptions] = None, @@ -670,13 +674,23 @@ class GeminiLiveLLMService(LLMService): Please use `http_options` to customize requests made by the API client. - model: Model identifier to use. Defaults to "models/gemini-2.5-flash-native-audio-preview-12-2025". + model: Model identifier to use. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(model=...)`` instead. + voice_id: TTS voice identifier. Defaults to "Charon". start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. system_instruction: System prompt for the model. Defaults to None. tools: Tools/functions available to the model. Defaults to None. - params: Configuration parameters for the model. Defaults to InputParams(). + params: Configuration parameters for the model. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(...)`` instead. + + settings: Gemini Live LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. inference_on_context_initialization: Whether to generate a response when context is first set. Defaults to True. file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint. @@ -694,43 +708,49 @@ 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() + _params = params or InputParams() + + 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, + 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 {}, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( base_url=base_url, - settings=GeminiLiveLLMSettings( - model=model, - frequency_penalty=params.frequency_penalty, - max_tokens=params.max_tokens, - presence_penalty=params.presence_penalty, - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - modalities=params.modalities, - language=language_to_gemini_language(params.language) - if params.language - else "en-US", - media_resolution=params.media_resolution, - vad=params.vad, - context_window_compression=params.context_window_compression.model_dump() - if params.context_window_compression - else {}, - thinking=params.thinking or {}, - enable_affective_dialog=params.enable_affective_dialog or False, - proactivity=params.proactivity or {}, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), + settings=default_settings, **kwargs, ) self._last_sent_time = 0 self._base_url = base_url self._voice_id = voice_id - self._language_code = params.language + self._language_code = _params.language self._system_instruction_from_init = system_instruction self._tools_from_init = tools @@ -760,11 +780,11 @@ class GeminiLiveLLMService(LLMService): self._sample_rate = 24000 - self._language = params.language + self._language = _params.language self._language_code = ( - language_to_gemini_language(params.language) if params.language else "en-US" + language_to_gemini_language(_params.language) if _params.language else "en-US" ) - self._vad_params = params.vad + self._vad_params = _params.vad # Reconnection tracking self._consecutive_failures = 0 diff --git a/src/pipecat/services/google/gemini_live/llm_vertex.py b/src/pipecat/services/google/gemini_live/llm_vertex.py index bb61033b3..eadcb66d1 100644 --- a/src/pipecat/services/google/gemini_live/llm_vertex.py +++ b/src/pipecat/services/google/gemini_live/llm_vertex.py @@ -19,9 +19,12 @@ from loguru import logger from pipecat.adapters.schemas.tools_schema import ToolsSchema from pipecat.services.google.gemini_live.llm import ( GeminiLiveLLMService, + GeminiLiveLLMSettings, HttpOptions, InputParams, + language_to_gemini_language, ) +from pipecat.services.settings import _warn_deprecated_param try: from google.auth import default @@ -51,13 +54,14 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): credentials_path: Optional[str] = None, location: str, project_id: str, - model="google/gemini-live-2.5-flash-native-audio", + model: Optional[str] = None, voice_id: str = "Charon", start_audio_paused: bool = False, start_video_paused: bool = False, system_instruction: Optional[str] = None, tools: Optional[Union[List[dict], ToolsSchema]] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiLiveLLMSettings] = None, inference_on_context_initialization: bool = True, file_api_base_url: str = "https://generativelanguage.googleapis.com/v1beta/files", http_options: Optional[HttpOptions] = None, @@ -70,7 +74,11 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): credentials_path: Path to the service account JSON file. location: GCP region for Vertex AI endpoint (e.g., "us-east4"). project_id: Google Cloud project ID. - model: Model identifier to use. Defaults to "models/gemini-live-2.5-flash-native-audio". + model: Model identifier to use. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(model=...)`` instead. + voice_id: TTS voice identifier. Defaults to "Charon". start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. @@ -78,6 +86,12 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService): tools: Tools/functions available to the model. Defaults to None. params: Configuration parameters for the model along with Vertex AI location and project ID. + + .. deprecated:: + Use ``settings=GeminiLiveLLMSettings(...)`` instead. + + settings: Gemini Live LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. inference_on_context_initialization: Whether to generate a response when context is first set. Defaults to True. file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint. @@ -95,24 +109,59 @@ 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) self._project_id = project_id self._location = location - # Call parent constructor with the obtained API key + # Build default_settings from deprecated args, then apply settings delta. + # We pass settings= to super() instead of model=/params= to avoid + # double deprecation warnings from the parent. + _params = params or InputParams() + + 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, + 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 {}, + ) + if settings is not None: + default_settings.apply_update(settings) + + # Call parent constructor with the obtained settings super().__init__( # api_key is required by parent class, but actually not used with # Vertex api_key="dummy", - model=model, voice_id=voice_id, start_audio_paused=start_audio_paused, start_video_paused=start_video_paused, system_instruction=system_instruction, tools=tools, - params=params, + settings=default_settings, inference_on_context_initialization=inference_on_context_initialization, file_api_base_url=file_api_base_url, http_options=http_options, diff --git a/src/pipecat/services/google/image.py b/src/pipecat/services/google/image.py index e69faf65e..3d7cf8c94 100644 --- a/src/pipecat/services/google/image.py +++ b/src/pipecat/services/google/image.py @@ -26,7 +26,7 @@ from pydantic import BaseModel, Field from pipecat.frames.frames import ErrorFrame, Frame, URLImageRawFrame from pipecat.services.google.utils import update_google_client_http_options from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import ImageGenSettings, _warn_deprecated_param try: from google import genai @@ -73,18 +73,33 @@ class GoogleImageGenService(ImageGenService): api_key: str, params: Optional[InputParams] = None, http_options: Optional[Any] = None, + settings: Optional[GoogleImageGenSettings] = None, **kwargs, ): """Initialize the GoogleImageGenService with API key and parameters. Args: api_key: Google AI API key for authentication. - params: Configuration parameters for image generation. Defaults to InputParams(). + params: Configuration parameters for image generation. + + .. deprecated:: 1.0 + Use ``settings=GoogleImageGenSettings(model=...)`` instead. + http_options: HTTP options for the client. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent ImageGenService. """ + if params is not None: + _warn_deprecated_param("params", "GoogleImageGenSettings") + params = params or GoogleImageGenService.InputParams() - super().__init__(settings=GoogleImageGenSettings(model=params.model), **kwargs) + + default_settings = GoogleImageGenSettings(model=params.model) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._params = params # Add client header diff --git a/src/pipecat/services/google/llm.py b/src/pipecat/services/google/llm.py index 37ccfae9a..5d5a87188 100644 --- a/src/pipecat/services/google/llm.py +++ b/src/pipecat/services/google/llm.py @@ -58,7 +58,13 @@ from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAIUserContextAggregator, ) -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + LLMSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.utils.tracing.service_decorators import traced_llm # Suppress gRPC fork warnings @@ -748,6 +754,9 @@ class GoogleLLMService(LLMService): class InputParams(BaseModel): """Input parameters for Google AI models. + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + Parameters: max_tokens: Maximum number of tokens to generate. temperature: Sampling temperature between 0.0 and 2.0. @@ -773,8 +782,9 @@ class GoogleLLMService(LLMService): self, *, api_key: str, - model: str = "gemini-2.5-flash", + model: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[List[Dict[str, Any]]] = None, tool_config: Optional[Dict[str, Any]] = None, @@ -785,33 +795,50 @@ class GoogleLLMService(LLMService): Args: api_key: Google AI API key for authentication. - model: Model name to use. Defaults to "gemini-2.0-flash". - params: Input parameters for the model. + model: Model name to use. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(model=...)`` instead. + + params: Optional model parameters for inference. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. system_instruction: System instruction/prompt for the model. tools: List of available tools/functions. tool_config: Configuration for tool usage. http_options: HTTP options for the client. **kwargs: Additional arguments passed to parent class. """ - params = params or GoogleLLMService.InputParams() + if model is not None: + _warn_deprecated_param("model", "GoogleLLMSettings", "model") + if params is not None: + _warn_deprecated_param("params", "GoogleLLMSettings") - super().__init__( - settings=GoogleLLMSettings( - model=model, - max_tokens=params.max_tokens, - temperature=params.temperature, - top_k=params.top_k, - top_p=params.top_p, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - thinking=params.thinking, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), - **kwargs, + _params = params or GoogleLLMService.InputParams() + + 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, + 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 {}, ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._api_key = api_key self._system_instruction = system_instruction diff --git a/src/pipecat/services/google/llm_openai.py b/src/pipecat/services/google/llm_openai.py index 5d396b583..22703ae55 100644 --- a/src/pipecat/services/google/llm_openai.py +++ b/src/pipecat/services/google/llm_openai.py @@ -12,6 +12,7 @@ API format through Google's Gemini API OpenAI compatibility layer. import json import os +from typing import Optional from openai import AsyncStream from openai.types.chat import ChatCompletionChunk @@ -26,7 +27,9 @@ from loguru import logger from pipecat.frames.frames import LLMTextFrame from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class GoogleLLMOpenAIBetaService(OpenAILLMService): @@ -52,7 +55,8 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): *, api_key: str, base_url: str = "https://generativelanguage.googleapis.com/v1beta/openai/", - model: str = "gemini-2.0-flash", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Google LLM service. @@ -61,6 +65,12 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): api_key: Google API key for authentication. base_url: Base URL for Google's OpenAI-compatible API. model: Google model name to use (e.g., "gemini-2.0-flash"). + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent OpenAILLMService. """ import warnings @@ -74,7 +84,14 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService): stacklevel=2, ) - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "gemini-2.0-flash") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) async def _process_context(self, context: OpenAILLMContext): functions_list = [] diff --git a/src/pipecat/services/google/llm_vertex.py b/src/pipecat/services/google/llm_vertex.py index ef222c97e..9258a4d67 100644 --- a/src/pipecat/services/google/llm_vertex.py +++ b/src/pipecat/services/google/llm_vertex.py @@ -20,7 +20,8 @@ from typing import Optional from loguru import logger -from pipecat.services.google.llm import GoogleLLMService +from pipecat.services.google.llm import GoogleLLMService, GoogleLLMSettings +from pipecat.services.settings import _warn_deprecated_param try: from google.auth import default @@ -99,10 +100,11 @@ class GoogleVertexLLMService(GoogleLLMService): *, credentials: Optional[str] = None, credentials_path: Optional[str] = None, - model: str = "gemini-2.5-flash", + model: Optional[str] = None, location: Optional[str] = None, project_id: Optional[str] = None, params: Optional[GoogleLLMService.InputParams] = None, + settings: Optional[GoogleLLMSettings] = None, system_instruction: Optional[str] = None, tools: Optional[list] = None, tool_config: Optional[dict] = None, @@ -115,9 +117,20 @@ class GoogleVertexLLMService(GoogleLLMService): credentials: JSON string of service account credentials. credentials_path: Path to the service account JSON file. model: Model identifier (e.g., "gemini-2.5-flash"). + + .. deprecated:: + Use ``settings=GoogleLLMSettings(model=...)`` instead. + location: GCP region for Vertex AI endpoint (e.g., "us-east4"). project_id: Google Cloud project ID. params: Input parameters for the model. + + .. deprecated:: + Use ``settings=GoogleLLMSettings(...)`` instead. + + settings: Runtime-updatable settings for this service. When both + deprecated parameters and *settings* are provided, *settings* + values take precedence. system_instruction: System instruction/prompt for the model. tools: List of available tools/functions. tool_config: Configuration for tool usage. @@ -135,6 +148,11 @@ 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 if params and isinstance(params, GoogleVertexLLMService.InputParams): # Extract location and project_id from params if not provided @@ -170,12 +188,30 @@ class GoogleVertexLLMService(GoogleLLMService): self._project_id = project_id self._location = location + # Build default_settings from deprecated args + _params = params or GoogleLLMService.InputParams() + 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, + 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 {}, + ) + if settings is not None: + default_settings.apply_update(settings) + # Call parent constructor with dummy api_key # (api_key is required by parent class, but not actually used with Vertex) super().__init__( api_key="dummy", - model=model, - params=params, + settings=default_settings, system_instruction=system_instruction, tools=tools, tool_config=tool_config, diff --git a/src/pipecat/services/google/stt.py b/src/pipecat/services/google/stt.py index 95d91d462..818df0214 100644 --- a/src/pipecat/services/google/stt.py +++ b/src/pipecat/services/google/stt.py @@ -36,7 +36,7 @@ from pipecat.frames.frames import ( StartFrame, TranscriptionFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import GOOGLE_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -425,6 +425,9 @@ class GoogleSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for Google Speech-to-Text. + .. deprecated:: 1.0 + Use ``settings=GoogleSTTSettings(...)`` instead. + Parameters: languages: Single language or list of recognition languages. First language is primary. model: Speech recognition model to use. @@ -484,6 +487,7 @@ class GoogleSTTService(STTService): location: str = "global", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleSTTSettings] = None, ttfs_p99_latency: Optional[float] = GOOGLE_TTFS_P99, **kwargs, ): @@ -495,30 +499,43 @@ class GoogleSTTService(STTService): location: Google Cloud location (e.g., "global", "us-central1"). sample_rate: Audio sample rate in Hertz. params: Configuration parameters for the service. + + .. deprecated:: 1.0 + Use ``settings=GoogleSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + ``params``, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - params = params or GoogleSTTService.InputParams() + if params is not None: + _warn_deprecated_param("params", "GoogleSTTSettings") + + _params = params or GoogleSTTService.InputParams() + + default_settings = GoogleSTTSettings( + language=None, + languages=list(_params.language_list), + language_codes=None, + model=_params.model, + use_separate_recognition_per_channel=_params.use_separate_recognition_per_channel, + enable_automatic_punctuation=_params.enable_automatic_punctuation, + enable_spoken_punctuation=_params.enable_spoken_punctuation, + enable_spoken_emojis=_params.enable_spoken_emojis, + profanity_filter=_params.profanity_filter, + enable_word_time_offsets=_params.enable_word_time_offsets, + enable_word_confidence=_params.enable_word_confidence, + enable_interim_results=_params.enable_interim_results, + enable_voice_activity_events=_params.enable_voice_activity_events, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=GoogleSTTSettings( - language=None, - languages=list(params.language_list), - language_codes=None, - model=params.model, - use_separate_recognition_per_channel=params.use_separate_recognition_per_channel, - enable_automatic_punctuation=params.enable_automatic_punctuation, - enable_spoken_punctuation=params.enable_spoken_punctuation, - enable_spoken_emojis=params.enable_spoken_emojis, - profanity_filter=params.profanity_filter, - enable_word_time_offsets=params.enable_word_time_offsets, - enable_word_confidence=params.enable_word_confidence, - enable_interim_results=params.enable_interim_results, - enable_voice_activity_events=params.enable_voice_activity_events, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/google/tts.py b/src/pipecat/services/google/tts.py index 6c71977a0..86ec845a5 100644 --- a/src/pipecat/services/google/tts.py +++ b/src/pipecat/services/google/tts.py @@ -37,7 +37,13 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + TTSSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language @@ -560,6 +566,9 @@ class GoogleHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Google HTTP TTS voice customization. + .. deprecated:: 1.0 + Use ``GoogleHttpTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: pitch: Voice pitch adjustment (e.g., "+2st", "-50%"). rate: Speaking rate adjustment (e.g., "slow", "fast", "125%"). Used for SSML prosody tags (non-Chirp voices). @@ -586,9 +595,10 @@ class GoogleHttpTTSService(TTSService): credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "en-US-Chirp3-HD-Charon", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GoogleHttpTTSSettings] = None, **kwargs, ): """Initializes the Google HTTP TTS service. @@ -598,28 +608,47 @@ class GoogleHttpTTSService(TTSService): credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Google TTS voice identifier (e.g., "en-US-Standard-A"). + + .. deprecated:: 1.0 + Use ``settings=GoogleHttpTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses default. params: Voice customization parameters including pitch, rate, volume, etc. + + .. deprecated:: 1.0 + Use ``settings=GoogleHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or GoogleHttpTTSService.InputParams() + 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() + + 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", + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=GoogleHttpTTSSettings( - model=None, - pitch=params.pitch, - rate=params.rate, - speaking_rate=params.speaking_rate, - volume=params.volume, - emphasis=params.emphasis, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - gender=params.gender, - google_style=params.google_style, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -987,6 +1016,9 @@ class GoogleTTSService(GoogleBaseTTSService): class InputParams(BaseModel): """Input parameters for Google streaming TTS configuration. + .. deprecated:: 1.0 + Use ``GoogleStreamTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English. speaking_rate: The speaking rate, in the range [0.25, 2.0]. @@ -1001,10 +1033,11 @@ class GoogleTTSService(GoogleBaseTTSService): credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "en-US-Chirp3-HD-Charon", + voice_id: Optional[str] = None, voice_cloning_key: Optional[str] = None, sample_rate: Optional[int] = None, - params: InputParams = InputParams(), + params: Optional[InputParams] = None, + settings: Optional[GoogleStreamTTSSettings] = None, **kwargs, ): """Initializes the Google streaming TTS service. @@ -1014,23 +1047,42 @@ class GoogleTTSService(GoogleBaseTTSService): credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Google TTS voice identifier (e.g., "en-US-Chirp3-HD-Charon"). + + .. deprecated:: 1.0 + Use ``settings=GoogleStreamTTSSettings(voice=...)`` instead. + voice_cloning_key: The voice cloning key for Chirp 3 custom voices. sample_rate: Audio sample rate in Hz. If None, uses default. params: Language configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=GoogleStreamTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or GoogleTTSService.InputParams() + 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() + + 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", + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=GoogleStreamTTSSettings( - model=None, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - speaking_rate=params.speaking_rate, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -1170,6 +1222,9 @@ class GeminiTTSService(GoogleBaseTTSService): class InputParams(BaseModel): """Input parameters for Gemini TTS configuration. + .. deprecated:: 1.0 + Use ``GeminiTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English. prompt: Optional style instructions for how to synthesize the content. @@ -1186,13 +1241,14 @@ class GeminiTTSService(GoogleBaseTTSService): self, *, api_key: Optional[str] = None, - model: str = "gemini-2.5-flash-tts", + model: Optional[str] = None, credentials: Optional[str] = None, credentials_path: Optional[str] = None, location: Optional[str] = None, - voice_id: str = "Kore", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[GeminiTTSSettings] = None, **kwargs, ): """Initializes the Gemini TTS service. @@ -1206,12 +1262,26 @@ class GeminiTTSService(GoogleBaseTTSService): model: Gemini TTS model to use. Must be a TTS model like "gemini-2.5-flash-tts" or "gemini-2.5-pro-tts". + + .. deprecated:: 1.0 + Use ``settings=GeminiTTSSettings(model=...)`` instead. + credentials: JSON string containing Google Cloud service account credentials. credentials_path: Path to Google Cloud service account JSON file. location: Google Cloud location for regional endpoint (e.g., "us-central1"). voice_id: Voice name from the available Gemini voices. + + .. deprecated:: 1.0 + Use ``settings=GeminiTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate in Hz. If None, uses Google's default 24kHz. params: TTS configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=GeminiTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ # Handle deprecated api_key parameter @@ -1222,29 +1292,40 @@ 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() + _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.") + 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, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, - settings=GeminiTTSSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "en-US", - prompt=params.prompt, - multi_speaker=params.multi_speaker, - speaker_configs=params.speaker_configs, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/gradium/stt.py b/src/pipecat/services/gradium/stt.py index ac35c6e52..e1d2b74d4 100644 --- a/src/pipecat/services/gradium/stt.py +++ b/src/pipecat/services/gradium/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 GRADIUM_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -91,6 +91,9 @@ class GradiumSTTService(WebsocketSTTService): class InputParams(BaseModel): """Configuration parameters for Gradium STT API. + .. deprecated:: 1.0 + Use ``settings=GradiumSTTSettings(...)`` instead. + Parameters: language: Expected language of the audio (e.g., "en", "es", "fr"). This helps ground the model to a specific language and improve @@ -111,6 +114,7 @@ class GradiumSTTService(WebsocketSTTService): api_endpoint_base_url: str = "wss://eu.api.gradium.ai/api/speech/asr", params: Optional[InputParams] = None, json_config: Optional[str] = None, + settings: Optional[GradiumSTTSettings] = None, ttfs_p99_latency: Optional[float] = GRADIUM_TTFS_P99, **kwargs, ): @@ -120,11 +124,17 @@ class GradiumSTTService(WebsocketSTTService): api_key: Gradium API key for authentication. api_endpoint_base_url: WebSocket endpoint URL. Defaults to Gradium's streaming endpoint. params: Configuration parameters for language and delay settings. + + .. deprecated:: 1.0 + Use ``settings=GradiumSTTSettings(...)`` instead. + json_config: Optional JSON configuration string for additional model settings. .. deprecated:: 0.0.101 Use `params` instead for type-safe configuration. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent STTService class. @@ -138,16 +148,23 @@ class GradiumSTTService(WebsocketSTTService): stacklevel=2, ) - params = params or GradiumSTTService.InputParams() + if params is not None: + _warn_deprecated_param("params", "GradiumSTTSettings") + + _params = params or GradiumSTTService.InputParams() + + default_settings = GradiumSTTSettings( + model=None, + language=_params.language, + delay_in_frames=_params.delay_in_frames or None, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=SAMPLE_RATE, ttfs_p99_latency=ttfs_p99_latency, - settings=GradiumSTTSettings( - model=None, - language=params.language, - delay_in_frames=params.delay_in_frames or None, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/gradium/tts.py b/src/pipecat/services/gradium/tts.py index c8a83a7f2..75455cf54 100644 --- a/src/pipecat/services/gradium/tts.py +++ b/src/pipecat/services/gradium/tts.py @@ -22,7 +22,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -57,6 +57,9 @@ class GradiumTTSService(AudioContextTTSService): class InputParams(BaseModel): """Configuration parameters for Gradium TTS service. + .. deprecated:: 1.0 + Use ``GradiumTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temp: Temperature to be used for generation, defaults to 0.6. """ @@ -67,11 +70,12 @@ class GradiumTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str = "YTpq7expH9539ERJ", + voice_id: Optional[str] = None, url: str = "wss://eu.api.gradium.ai/api/speech/tts", - model: str = "default", + model: Optional[str] = None, json_config: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[GradiumTTSSettings] = None, **kwargs, ): """Initialize the Gradium TTS service. @@ -79,13 +83,41 @@ class GradiumTTSService(AudioContextTTSService): Args: api_key: Gradium API key for authentication. voice_id: the voice identifier. + + .. deprecated:: 1.0 + Use ``settings=GradiumTTSSettings(voice=...)`` instead. + url: Gradium websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=GradiumTTSSettings(model=...)`` instead. + json_config: Optional JSON configuration string for additional model settings. params: Additional configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=GradiumTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent class. """ - params = params or GradiumTTSService.InputParams() + 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") + + default_settings = GradiumTTSSettings( + model=model or "default", + voice=voice_id or "YTpq7expH9539ERJ", + language=None, + output_format="pcm", + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_stop_frames=True, @@ -93,12 +125,7 @@ class GradiumTTSService(AudioContextTTSService): pause_frame_processing=True, supports_word_timestamps=True, sample_rate=SAMPLE_RATE, - settings=GradiumTTSSettings( - model=model, - voice=voice_id, - language=None, - output_format="pcm", - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/grok/llm.py b/src/pipecat/services/grok/llm.py index fa905a92c..0ef6d36f2 100644 --- a/src/pipecat/services/grok/llm.py +++ b/src/pipecat/services/grok/llm.py @@ -12,6 +12,7 @@ and context aggregation functionality. """ from dataclasses import dataclass +from typing import Optional from loguru import logger @@ -22,11 +23,13 @@ from pipecat.processors.aggregators.llm_response import ( LLMUserAggregatorParams, ) from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import ( OpenAIAssistantContextAggregator, OpenAILLMService, OpenAIUserContextAggregator, ) +from pipecat.services.settings import _warn_deprecated_param @dataclass @@ -81,7 +84,8 @@ class GrokLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.x.ai/v1", - model: str = "grok-3-beta", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the GrokLLMService with API key and model. @@ -90,9 +94,22 @@ class GrokLLMService(OpenAILLMService): api_key: The API key for accessing Grok's API. base_url: The base URL for Grok API. Defaults to "https://api.x.ai/v1". model: The model identifier to use. Defaults to "grok-3-beta". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "grok-3-beta") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Initialize counters for token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 diff --git a/src/pipecat/services/grok/realtime/llm.py b/src/pipecat/services/grok/realtime/llm.py index 7a4e73806..87f5eaaaa 100644 --- a/src/pipecat/services/grok/realtime/llm.py +++ b/src/pipecat/services/grok/realtime/llm.py @@ -56,7 +56,7 @@ from pipecat.processors.aggregators.llm_response_universal import ( from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.utils.time import time_now_iso8601 from . import events @@ -126,6 +126,7 @@ class GrokRealtimeLLMService(LLMService): api_key: str, base_url: str = "wss://api.x.ai/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[GrokRealtimeLLMSettings] = None, start_audio_paused: bool = False, **kwargs, ): @@ -136,30 +137,46 @@ class GrokRealtimeLLMService(LLMService): base_url: WebSocket base URL for the realtime API. Defaults to "wss://api.x.ai/v1/realtime". session_properties: Configuration properties for the realtime session. + + .. deprecated:: + Use ``settings=GrokRealtimeLLMSettings(session_properties=...)`` + instead. + If None, uses default SessionProperties with voice "Ara". To set a different voice, configure it in session_properties: session_properties = events.SessionProperties(voice="Rex") Available voices: Ara, Rex, Sal, Eve, Leo. + settings: Grok Realtime LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. 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" + ) + + default_settings = GrokRealtimeLLMSettings( + model=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + session_properties=session_properties or events.SessionProperties(), + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( base_url=base_url, - settings=GrokRealtimeLLMSettings( - model=None, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/groq/llm.py b/src/pipecat/services/groq/llm.py index 9dae88c31..23cce68a2 100644 --- a/src/pipecat/services/groq/llm.py +++ b/src/pipecat/services/groq/llm.py @@ -6,9 +6,13 @@ """Groq LLM Service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class GroqLLMService(OpenAILLMService): @@ -23,7 +27,8 @@ class GroqLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.groq.com/openai/v1", - model: str = "llama-3.3-70b-versatile", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize Groq LLM service. @@ -32,9 +37,22 @@ class GroqLLMService(OpenAILLMService): api_key: The API key for accessing Groq's API. base_url: The base URL for Groq API. Defaults to "https://api.groq.com/openai/v1". model: The model identifier to use. Defaults to "llama-3.3-70b-versatile". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "llama-3.3-70b-versatile") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Groq API endpoint. diff --git a/src/pipecat/services/groq/stt.py b/src/pipecat/services/groq/stt.py index d51e93c68..8018ec702 100644 --- a/src/pipecat/services/groq/stt.py +++ b/src/pipecat/services/groq/stt.py @@ -8,8 +8,13 @@ from typing import Optional +from pipecat.services.settings import _warn_deprecated_param from pipecat.services.stt_latency import GROQ_TTFS_P99 -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language @@ -23,35 +28,75 @@ class GroqSTTService(BaseWhisperSTTService): def __init__( self, *, - model: str = "whisper-large-v3-turbo", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: str = "https://api.groq.com/openai/v1", - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[BaseWhisperSTTSettings] = None, ttfs_p99_latency: Optional[float] = GROQ_TTFS_P99, **kwargs, ): """Initialize Groq STT service. Args: - model: Whisper model to use. Defaults to "whisper-large-v3-turbo". + model: Whisper model to use. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(model=...)`` instead. + api_key: Groq API key. Defaults to None. base_url: API base URL. Defaults to "https://api.groq.com/openai/v1". - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(prompt=...)`` instead. + + temperature: Optional sampling temperature between 0 and 1. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ - super().__init__( + 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. + default_settings = BaseWhisperSTTSettings( model=model, - api_key=api_key, + language=self.language_to_service_language(language), base_url=base_url, - language=language, prompt=prompt, temperature=temperature, + ) + 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, ) diff --git a/src/pipecat/services/groq/tts.py b/src/pipecat/services/groq/tts.py index 901b786c0..c6cc46e23 100644 --- a/src/pipecat/services/groq/tts.py +++ b/src/pipecat/services/groq/tts.py @@ -21,7 +21,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language from pipecat.utils.tracing.service_decorators import traced_tts @@ -64,6 +64,9 @@ class GroqTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Groq TTS configuration. + .. deprecated:: 1.0 + Use ``settings=GroqTTSSettings(...)`` instead. + Parameters: language: Language for speech synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -80,9 +83,10 @@ class GroqTTSService(TTSService): api_key: str, output_format: str = "wav", params: Optional[InputParams] = None, - model_name: str = "canopylabs/orpheus-v1-english", - voice_id: str = "autumn", + model_name: Optional[str] = None, + voice_id: Optional[str] = None, sample_rate: Optional[int] = GROQ_SAMPLE_RATE, + settings: Optional[GroqTTSSettings] = None, **kwargs, ): """Initialize Groq TTS service. @@ -91,27 +95,52 @@ class GroqTTSService(TTSService): api_key: Groq API key for authentication. output_format: Audio output format. Defaults to "wav". params: Additional input parameters for voice customization. - model_name: TTS model to use. Defaults to "playai-tts". - voice_id: Voice identifier to use. Defaults to "Celeste-PlayAI". + + .. deprecated:: 1.0 + Use ``settings=GroqTTSSettings(...)`` instead. + + model_name: TTS model to use. + + .. deprecated:: 1.0 + Use ``settings=GroqTTSSettings(model=...)`` instead. + + voice_id: Voice identifier to use. + + .. deprecated:: 1.0 + Use ``settings=GroqTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. Must be 48000 Hz for Groq TTS. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService class. """ + if 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() + _params = params or GroqTTSService.InputParams() + + 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", + output_format=output_format, + speed=_params.speed, + groq_sample_rate=sample_rate, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( pause_frame_processing=True, sample_rate=sample_rate, - settings=GroqTTSSettings( - model=model_name, - voice=voice_id, - language=str(params.language) if params.language else "en", - output_format=output_format, - speed=params.speed, - groq_sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/heygen/video.py b/src/pipecat/services/heygen/video.py index 7f3624f35..020ecdfcf 100644 --- a/src/pipecat/services/heygen/video.py +++ b/src/pipecat/services/heygen/video.py @@ -45,6 +45,7 @@ from pipecat.services.heygen.client import ( HeyGenClient, ServiceType, ) +from pipecat.services.settings import ServiceSettings from pipecat.transports.base_transport import TransportParams # Using the same values that we do in the BaseOutputTransport @@ -80,6 +81,7 @@ class HeyGenVideoService(AIService): session: aiohttp.ClientSession, session_request: Optional[Union[LiveAvatarNewSessionRequest, NewSessionRequest]] = None, service_type: Optional[ServiceType] = None, + settings: Optional[ServiceSettings] = None, **kwargs, ) -> None: """Initialize the HeyGen video service. @@ -89,9 +91,15 @@ class HeyGenVideoService(AIService): session: HTTP client session for API requests session_request: Configuration for the HeyGen session service_type: Service type for the avatar session + settings: Runtime-updatable settings. HeyGen has no model concept, so this + is primarily used for the ``extra`` dict. **kwargs: Additional arguments passed to parent AIService """ - super().__init__(**kwargs) + default_settings = ServiceSettings(model=None) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._api_key = api_key self._session = session self._client: Optional[HeyGenClient] = None diff --git a/src/pipecat/services/hume/tts.py b/src/pipecat/services/hume/tts.py index 2a075ab36..35b6fbbc4 100644 --- a/src/pipecat/services/hume/tts.py +++ b/src/pipecat/services/hume/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -84,6 +84,9 @@ class HumeTTSService(TTSService): class InputParams(BaseModel): """Optional synthesis parameters for Hume TTS. + .. deprecated:: 1.0 + Use ``settings=HumeTTSSettings(...)`` instead. + Parameters: description: Natural-language acting directions (up to 100 characters). speed: Speaking-rate multiplier (0.5-2.0). @@ -98,9 +101,10 @@ class HumeTTSService(TTSService): self, *, api_key: Optional[str] = None, - voice_id: str, + voice_id: Optional[str] = None, params: Optional[InputParams] = None, sample_rate: Optional[int] = HUME_SAMPLE_RATE, + settings: Optional[HumeTTSSettings] = None, **kwargs, ) -> None: """Initialize the HumeTTSService. @@ -108,10 +112,25 @@ class HumeTTSService(TTSService): Args: api_key: Hume API key. If omitted, reads the ``HUME_API_KEY`` environment variable. voice_id: ID of the voice to use. Only voice IDs are supported; voice names are not. + + .. deprecated:: 1.0 + Use ``settings=HumeTTSSettings(voice=...)`` instead. + params: Optional synthesis controls (acting instructions, speed, trailing silence). + + .. deprecated:: 1.0 + Use ``settings=HumeTTSSettings(...)`` instead. + sample_rate: Output sample rate for emitted PCM frames. Defaults to 48_000 (Hume). + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ + 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=)") @@ -121,21 +140,25 @@ class HumeTTSService(TTSService): f"Hume TTS streams at {HUME_SAMPLE_RATE} Hz; configured sample_rate={sample_rate}" ) - params = params or HumeTTSService.InputParams() + _params = params or HumeTTSService.InputParams() + + default_settings = HumeTTSSettings( + model=None, + voice=voice_id, + language=None, # Not applicable here + description=_params.description, + speed=_params.speed, + trailing_silence=_params.trailing_silence, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, push_text_frames=False, push_stop_frames=True, supports_word_timestamps=True, - settings=HumeTTSSettings( - model=None, - voice=voice_id, - language=None, # Not applicable here - description=params.description, - speed=params.speed, - trailing_silence=params.trailing_silence, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/inworld/tts.py b/src/pipecat/services/inworld/tts.py index d3f64c16f..23c3b36e4 100644 --- a/src/pipecat/services/inworld/tts.py +++ b/src/pipecat/services/inworld/tts.py @@ -29,7 +29,7 @@ from pipecat import version as pipecat_version USER_AGENT = f"pipecat/{pipecat_version()}" from pydantic import BaseModel -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param try: from websockets.asyncio.client import connect as websocket_connect @@ -114,6 +114,9 @@ class InworldHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Inworld TTS configuration. + .. deprecated:: 1.0 + Use ``InworldTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temperature: Temperature for speech synthesis. speaking_rate: Speaking rate for speech synthesis. @@ -129,12 +132,13 @@ class InworldHttpTTSService(TTSService): *, api_key: str, aiohttp_session: aiohttp.ClientSession, - voice_id: str = "Ashley", - model: str = "inworld-tts-1.5-max", + voice_id: Optional[str] = None, + model: Optional[str] = None, streaming: bool = True, sample_rate: Optional[int] = None, encoding: str = "LINEAR16", - params: InputParams = None, + params: Optional[InputParams] = None, + settings: Optional[InworldTTSSettings] = None, **kwargs, ): """Initialize the Inworld TTS service. @@ -143,32 +147,57 @@ class InworldHttpTTSService(TTSService): api_key: Inworld API key. aiohttp_session: aiohttp ClientSession for HTTP requests. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(voice=...)`` instead. + model: ID of the model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(model=...)`` instead. + streaming: Whether to use streaming mode. sample_rate: Audio sample rate in Hz. encoding: Audio encoding format. params: Input parameters for Inworld TTS configuration. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent class. """ - params = params or InworldHttpTTSService.InputParams() + 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() + + default_settings = InworldTTSSettings( + model=model or "inworld-tts-1.5-max", + voice=voice_id or "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, + auto_mode=None, # Not applicable for HTTP TTS + apply_text_normalization=None, # Not applicable for HTTP TTS + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_text_frames=False, push_stop_frames=True, supports_word_timestamps=True, sample_rate=sample_rate, - settings=InworldTTSSettings( - model=model, - voice=voice_id, - language=None, - audio_encoding=encoding, - audio_sample_rate=0, - speaking_rate=params.speaking_rate, - temperature=params.temperature, - timestamp_transport_strategy=params.timestamp_transport_strategy, - auto_mode=None, # Not applicable for HTTP TTS - apply_text_normalization=None, # Not applicable for HTTP TTS - ), + settings=default_settings, **kwargs, ) @@ -477,6 +506,9 @@ class InworldTTSService(AudioContextTTSService): class InputParams(BaseModel): """Input parameters for Inworld WebSocket TTS configuration. + .. deprecated:: 1.0 + Use ``InworldTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: temperature: Temperature for speech synthesis. speaking_rate: Speaking rate for speech synthesis. @@ -503,12 +535,13 @@ class InworldTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str = "Ashley", - model: str = "inworld-tts-1.5-max", + voice_id: Optional[str] = None, + model: Optional[str] = None, url: str = "wss://api.inworld.ai/tts/v1/voice:streamBidirectional", sample_rate: Optional[int] = None, encoding: str = "LINEAR16", - params: InputParams = None, + params: Optional[InputParams] = None, + settings: Optional[InworldTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, append_trailing_space: bool = True, @@ -519,11 +552,25 @@ class InworldTTSService(AudioContextTTSService): Args: api_key: Inworld API key. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(voice=...)`` instead. + model: ID of the model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(model=...)`` instead. + url: URL of the Inworld WebSocket API. sample_rate: Audio sample rate in Hz. encoding: Audio encoding format. params: Input parameters for Inworld WebSocket TTS configuration. + + .. deprecated:: 1.0 + Use ``settings=InworldTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -533,7 +580,29 @@ class InworldTTSService(AudioContextTTSService): append_trailing_space: Whether to append a trailing space to text before sending to TTS. **kwargs: Additional arguments passed to the parent class. """ - params = params or InworldTTSService.InputParams() + 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() + + default_settings = InworldTTSSettings( + model=model or "inworld-tts-1.5-max", + voice=voice_id or "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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( push_text_frames=False, @@ -544,18 +613,7 @@ class InworldTTSService(AudioContextTTSService): aggregate_sentences=aggregate_sentences, text_aggregation_mode=text_aggregation_mode, append_trailing_space=append_trailing_space, - settings=InworldTTSSettings( - model=model, - voice=voice_id, - language=None, - audio_encoding=encoding, - audio_sample_rate=0, - speaking_rate=params.speaking_rate, - temperature=params.temperature, - apply_text_normalization=params.apply_text_normalization, - timestamp_transport_strategy=params.timestamp_transport_strategy, - auto_mode=params.auto_mode if params.auto_mode is not None else aggregate_sentences, - ), + settings=default_settings, **kwargs, ) @@ -564,8 +622,8 @@ class InworldTTSService(AudioContextTTSService): self._timestamp_type = "WORD" self._buffer_settings = { - "maxBufferDelayMs": params.max_buffer_delay_ms, - "bufferCharThreshold": params.buffer_char_threshold, + "maxBufferDelayMs": _params.max_buffer_delay_ms, + "bufferCharThreshold": _params.buffer_char_threshold, } self._receive_task = None diff --git a/src/pipecat/services/kokoro/tts.py b/src/pipecat/services/kokoro/tts.py index 4b35fa46d..fed53049c 100644 --- a/src/pipecat/services/kokoro/tts.py +++ b/src/pipecat/services/kokoro/tts.py @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -112,6 +112,9 @@ class KokoroTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Kokoro TTS configuration. + .. deprecated:: 1.0 + Use ``KokoroTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language to use for synthesis. """ @@ -121,35 +124,55 @@ class KokoroTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, model_path: Optional[str] = None, voices_path: Optional[str] = None, params: Optional[InputParams] = None, + settings: Optional[KokoroTTSSettings] = None, **kwargs, ): """Initialize the Kokoro TTS service. Args: voice_id: Voice identifier to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=KokoroTTSSettings(voice=...)`` instead. + model_path: Path to the kokoro ONNX model file. Defaults to auto-downloaded file. voices_path: Path to the voices binary file. Defaults to auto-downloaded file. params: Configuration parameters for synthesis. + + .. deprecated:: 1.0 + Use ``settings=KokoroTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent `TTSService`. """ - params = params or KokoroTTSService.InputParams() + 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() + + default_settings = KokoroTTSSettings( + model=None, + voice=voice_id, + language=language_to_kokoro_language(_params.language), + lang_code=language_to_kokoro_language(_params.language), + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=KokoroTTSSettings( - model=None, - voice=voice_id, - language=language_to_kokoro_language(params.language), - lang_code=language_to_kokoro_language(params.language), - ), + settings=default_settings, **kwargs, ) - self._lang_code = language_to_kokoro_language(params.language) + self._lang_code = language_to_kokoro_language(_params.language) model = 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" diff --git a/src/pipecat/services/lmnt/tts.py b/src/pipecat/services/lmnt/tts.py index a2c500ca2..1e7cff994 100644 --- a/src/pipecat/services/lmnt/tts.py +++ b/src/pipecat/services/lmnt/tts.py @@ -24,7 +24,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -98,10 +98,11 @@ class LmntTTSService(InterruptibleTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, language: Language = Language.EN, - model: str = "blizzard", + model: Optional[str] = None, + settings: Optional[LmntTTSSettings] = None, **kwargs, ): """Initialize the LMNT TTS service. @@ -109,21 +110,40 @@ class LmntTTSService(InterruptibleTTSService): Args: api_key: LMNT API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=LmntTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses default. language: Language for synthesis. Defaults to English. - model: TTS model to use. Defaults to "blizzard". + model: TTS model to use. + + .. deprecated:: 1.0 + Use ``settings=LmntTTSSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ + if voice_id is not None: + _warn_deprecated_param("voice_id", "LmntTTSSettings", "voice") + if model is not None: + _warn_deprecated_param("model", "LmntTTSSettings", "model") + + default_settings = LmntTTSSettings( + model=model or "blizzard", + voice=voice_id, + language=self.language_to_service_language(language), + format="raw", + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( push_stop_frames=True, pause_frame_processing=True, sample_rate=sample_rate, - settings=LmntTTSSettings( - model=model, - voice=voice_id, - language=self.language_to_service_language(language), - format="raw", - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/minimax/tts.py b/src/pipecat/services/minimax/tts.py index 116d24a34..602654e2f 100644 --- a/src/pipecat/services/minimax/tts.py +++ b/src/pipecat/services/minimax/tts.py @@ -26,7 +26,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -166,6 +166,9 @@ class MiniMaxHttpTTSService(TTSService): class InputParams(BaseModel): """Configuration parameters for MiniMax TTS. + .. deprecated:: 1.0 + Use ``MiniMaxTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for TTS generation. Supports 40 languages. Note: Filipino, Tamil, and Persian require speech-2.6-* models. @@ -201,11 +204,12 @@ class MiniMaxHttpTTSService(TTSService): api_key: str, base_url: str = "https://api.minimax.io/v1/t2a_v2", group_id: str, - model: str = "speech-02-turbo", - voice_id: str = "Calm_Woman", + model: Optional[str] = None, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[MiniMaxTTSSettings] = None, **kwargs, ): """Initialize the MiniMax TTS service. @@ -221,50 +225,45 @@ class MiniMaxHttpTTSService(TTSService): "speech-2.6-hd", "speech-2.6-turbo" (latest, supports Filipino/Tamil/Persian), "speech-02-hd", "speech-02-turbo", "speech-01-hd", "speech-01-turbo". + + .. deprecated:: 1.0 + Use ``settings=MiniMaxTTSSettings(model=...)`` instead. + voice_id: Voice identifier. Defaults to "Calm_Woman". + + .. deprecated:: 1.0 + Use ``settings=MiniMaxTTSSettings(voice=...)`` instead. + aiohttp_session: aiohttp.ClientSession for API communication. sample_rate: Output audio sample rate in Hz. If None, uses pipeline default. params: Additional configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=MiniMaxTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or MiniMaxHttpTTSService.InputParams() + 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") - super().__init__( - sample_rate=sample_rate, - settings=MiniMaxTTSSettings( - model=model, - voice=voice_id, - language=None, - stream=True, - speed=params.speed, - volume=params.volume, - pitch=params.pitch, - language_boost=None, - emotion=None, - text_normalization=None, - latex_read=None, - audio_bitrate=128000, - audio_format="pcm", - audio_channel=1, - audio_sample_rate=0, - ), - **kwargs, - ) + _params = params or MiniMaxHttpTTSService.InputParams() - self._api_key = api_key - self._group_id = group_id - self._base_url = f"{base_url}?GroupId={group_id}" - self._session = aiohttp_session - - # Add language boost if provided - if params.language: - service_lang = self.language_to_service_language(params.language) + # Resolve language boost + language_boost = None + if _params.language: + service_lang = self.language_to_service_language(_params.language) if service_lang: - self._settings.language_boost = service_lang + language_boost = service_lang - # Add optional emotion if provided - if params.emotion: - # Validate emotion is in the supported list + # Resolve emotion + emotion = None + if _params.emotion: supported_emotions = [ "happy", "sad", @@ -275,15 +274,16 @@ class MiniMaxHttpTTSService(TTSService): "neutral", "fluent", ] - if params.emotion in supported_emotions: - self._settings.emotion = params.emotion + if _params.emotion in supported_emotions: + emotion = _params.emotion else: logger.warning( - f"Unsupported emotion: {params.emotion}. Supported emotions: {supported_emotions}" + f"Unsupported emotion: {_params.emotion}. Supported emotions: {supported_emotions}" ) - # If `english_normalization`, add `text_normalization` and print warning - if params.english_normalization is not None: + # Resolve text_normalization + text_normalization = None + if _params.english_normalization is not None: import warnings with warnings.catch_warnings(): @@ -292,15 +292,40 @@ class MiniMaxHttpTTSService(TTSService): "Parameter `english_normalization` is deprecated and will be removed in a future version. Use `text_normalization` instead.", DeprecationWarning, ) - self._settings.text_normalization = params.english_normalization + text_normalization = _params.english_normalization + if _params.text_normalization is not None: + text_normalization = _params.text_normalization - # Add text_normalization if provided (corrected parameter name) - if params.text_normalization is not None: - self._settings.text_normalization = params.text_normalization + default_settings = MiniMaxTTSSettings( + model=model or "speech-02-turbo", + voice=voice_id or "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, + audio_bitrate=128000, + audio_format="pcm", + audio_channel=1, + audio_sample_rate=0, + ) + if settings is not None: + default_settings.apply_update(settings) - # Add latex_read if provided - if params.latex_read is not None: - self._settings.latex_read = params.latex_read + super().__init__( + sample_rate=sample_rate, + settings=default_settings, + **kwargs, + ) + + self._api_key = api_key + self._group_id = group_id + self._base_url = f"{base_url}?GroupId={group_id}" + self._session = aiohttp_session def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. diff --git a/src/pipecat/services/mistral/llm.py b/src/pipecat/services/mistral/llm.py index 984ffb7dd..e4249741e 100644 --- a/src/pipecat/services/mistral/llm.py +++ b/src/pipecat/services/mistral/llm.py @@ -6,14 +6,16 @@ """Mistral LLM service implementation using OpenAI-compatible interface.""" -from typing import List, Sequence +from typing import List, Optional, Sequence from loguru import logger from openai.types.chat import ChatCompletionMessageParam from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams from pipecat.frames.frames import FunctionCallFromLLM +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class MistralLLMService(OpenAILLMService): @@ -28,7 +30,8 @@ class MistralLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.mistral.ai/v1", - model: str = "mistral-small-latest", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Mistral LLM service. @@ -37,9 +40,22 @@ class MistralLLMService(OpenAILLMService): api_key: The API key for accessing Mistral's API. base_url: The base URL for Mistral API. Defaults to "https://api.mistral.ai/v1". model: The model identifier to use. Defaults to "mistral-small-latest". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "mistral-small-latest") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Mistral API endpoint. diff --git a/src/pipecat/services/moondream/vision.py b/src/pipecat/services/moondream/vision.py index 53b98b77a..db449d7ed 100644 --- a/src/pipecat/services/moondream/vision.py +++ b/src/pipecat/services/moondream/vision.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( VisionFullResponseStartFrame, VisionTextFrame, ) -from pipecat.services.settings import VisionSettings +from pipecat.services.settings import VisionSettings, _warn_deprecated_param from pipecat.services.vision_service import VisionService try: @@ -80,17 +80,36 @@ class MoondreamService(VisionService): """ def __init__( - self, *, model="vikhyatk/moondream2", revision="2025-01-09", use_cpu=False, **kwargs + self, + *, + model: Optional[str] = None, + revision="2025-01-09", + use_cpu=False, + settings: Optional[MoondreamSettings] = None, + **kwargs, ): """Initialize the Moondream service. Args: model: Hugging Face model identifier for the Moondream model. + + .. deprecated:: 1.0 + Use ``settings=MoondreamSettings(model=...)`` instead. + revision: Specific model revision to use. use_cpu: Whether to force CPU usage instead of hardware acceleration. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent VisionService. """ - super().__init__(settings=MoondreamSettings(model=model), **kwargs) + if model is not None: + _warn_deprecated_param("model", "MoondreamSettings", "model") + + default_settings = MoondreamSettings(model=model or "vikhyatk/moondream2") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) if not use_cpu: device, dtype = detect_device() @@ -101,7 +120,7 @@ class MoondreamService(VisionService): logger.debug("Loading Moondream model...") self._model = AutoModelForCausalLM.from_pretrained( - model, + self._settings.model, trust_remote_code=True, revision=revision, device_map={"": device}, diff --git a/src/pipecat/services/neuphonic/tts.py b/src/pipecat/services/neuphonic/tts.py index 63411c3eb..21c7b57dd 100644 --- a/src/pipecat/services/neuphonic/tts.py +++ b/src/pipecat/services/neuphonic/tts.py @@ -35,7 +35,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -102,6 +102,9 @@ class NeuphonicTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Input parameters for Neuphonic TTS configuration. + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -119,6 +122,7 @@ class NeuphonicTTSService(InterruptibleTTSService): sample_rate: Optional[int] = 22050, encoding: str = "pcm_linear", params: Optional[InputParams] = None, + settings: Optional[NeuphonicTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -128,10 +132,20 @@ class NeuphonicTTSService(InterruptibleTTSService): Args: api_key: Neuphonic API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(voice=...)`` instead. + url: WebSocket URL for the Neuphonic API. sample_rate: Audio sample rate in Hz. Defaults to 22050. encoding: Audio encoding format. Defaults to "pcm_linear". params: Additional input parameters for TTS configuration. + + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -140,7 +154,23 @@ class NeuphonicTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent InterruptibleTTSService. """ - params = params or NeuphonicTTSService.InputParams() + 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() + + default_settings = NeuphonicTTSSettings( + model=None, + language=self.language_to_service_language(_params.language), + speed=_params.speed, + encoding=encoding, + sampling_rate=sample_rate, + voice=voice_id, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( aggregate_sentences=aggregate_sentences, @@ -148,14 +178,7 @@ class NeuphonicTTSService(InterruptibleTTSService): push_stop_frames=True, stop_frame_timeout_s=2.0, sample_rate=sample_rate, - settings=NeuphonicTTSSettings( - model=None, - language=self.language_to_service_language(params.language), - speed=params.speed, - encoding=encoding, - sampling_rate=sample_rate, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -418,6 +441,9 @@ class NeuphonicHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Neuphonic HTTP TTS configuration. + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. speed: Speech speed multiplier. Defaults to 1.0. @@ -436,6 +462,7 @@ class NeuphonicHttpTTSService(TTSService): sample_rate: Optional[int] = 22050, encoding: Optional[str] = "pcm_linear", params: Optional[InputParams] = None, + settings: Optional[NeuphonicTTSSettings] = None, **kwargs, ): """Initialize the Neuphonic HTTP TTS service. @@ -443,25 +470,44 @@ class NeuphonicHttpTTSService(TTSService): Args: api_key: Neuphonic API key for authentication. voice_id: ID of the voice to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. url: Base URL for the Neuphonic HTTP API. sample_rate: Audio sample rate in Hz. Defaults to 22050. encoding: Audio encoding format. Defaults to "pcm_linear". params: Additional input parameters for TTS configuration. + + .. deprecated:: 1.0 + Use ``settings=NeuphonicTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or NeuphonicHttpTTSService.InputParams() + 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() + + default_settings = NeuphonicTTSSettings( + model=None, + voice=voice_id, + language=self.language_to_service_language(_params.language) or "en", + speed=_params.speed, + encoding=encoding, + sampling_rate=sample_rate, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=NeuphonicTTSSettings( - model=None, - voice=voice_id, - language=self.language_to_service_language(params.language) or "en", - speed=params.speed, - encoding=encoding, - sampling_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/nvidia/llm.py b/src/pipecat/services/nvidia/llm.py index c5db58f31..ef4afe848 100644 --- a/src/pipecat/services/nvidia/llm.py +++ b/src/pipecat/services/nvidia/llm.py @@ -10,10 +10,14 @@ This module provides a service for interacting with NVIDIA's NIM (NVIDIA Inferen Microservice) API while maintaining compatibility with the OpenAI-style interface. """ +from typing import Optional + from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class NvidiaLLMService(OpenAILLMService): @@ -29,7 +33,8 @@ class NvidiaLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://integrate.api.nvidia.com/v1", - model: str = "nvidia/llama-3.1-nemotron-70b-instruct", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the NvidiaLLMService. @@ -37,10 +42,26 @@ class NvidiaLLMService(OpenAILLMService): Args: api_key: The API key for accessing NVIDIA's NIM API. base_url: The base URL for NIM API. Defaults to "https://integrate.api.nvidia.com/v1". - model: The model identifier to use. Defaults to "nvidia/llama-3.1-nemotron-70b-instruct". + model: The model identifier to use. Defaults to + "nvidia/llama-3.1-nemotron-70b-instruct". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings( + model=model or "nvidia/llama-3.1-nemotron-70b-instruct" + ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Counters for accumulating token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 diff --git a/src/pipecat/services/nvidia/stt.py b/src/pipecat/services/nvidia/stt.py index 950515096..7f9c28f8f 100644 --- a/src/pipecat/services/nvidia/stt.py +++ b/src/pipecat/services/nvidia/stt.py @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( StartFrame, TranscriptionFrame, ) -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import NVIDIA_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService, STTService from pipecat.transcriptions.language import Language, resolve_language @@ -130,6 +130,9 @@ class NvidiaSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for NVIDIA Riva STT service. + .. deprecated:: 1.0 + Use ``settings=NvidiaSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. Defaults to EN_US. """ @@ -148,6 +151,7 @@ class NvidiaSTTService(STTService): sample_rate: Optional[int] = None, params: Optional[InputParams] = None, use_ssl: bool = True, + settings: Optional[NvidiaSTTSettings] = None, ttfs_p99_latency: Optional[float] = NVIDIA_TTFS_P99, **kwargs, ): @@ -159,20 +163,33 @@ class NvidiaSTTService(STTService): model_function_map: Mapping containing 'function_id' and 'model_name' for the ASR model. sample_rate: Audio sample rate in Hz. If None, uses pipeline default. params: Additional configuration parameters for NVIDIA Riva. + + .. deprecated:: 1.0 + Use ``settings=NvidiaSTTSettings(...)`` instead. + use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. """ - params = params or NvidiaSTTService.InputParams() + if params is not None: + _warn_deprecated_param("params", "NvidiaSTTSettings") + + _params = params or NvidiaSTTService.InputParams() + + default_settings = NvidiaSTTSettings( + model=model_function_map.get("model_name"), + language=_params.language, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=NvidiaSTTSettings( - model=model_function_map.get("model_name"), - language=params.language, - ), + settings=default_settings, **kwargs, ) @@ -421,6 +438,9 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): class InputParams(BaseModel): """Configuration parameters for NVIDIA Riva segmented STT service. + .. deprecated:: 1.0 + Use ``settings=NvidiaSegmentedSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. Defaults to EN_US. profanity_filter: Whether to filter profanity from results. @@ -449,6 +469,7 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): sample_rate: Optional[int] = None, params: Optional[InputParams] = None, use_ssl: bool = True, + settings: Optional[NvidiaSegmentedSTTSettings] = None, ttfs_p99_latency: Optional[float] = NVIDIA_TTFS_P99, **kwargs, ): @@ -460,26 +481,39 @@ class NvidiaSegmentedSTTService(SegmentedSTTService): model_function_map: Mapping of model name and its corresponding NVIDIA Cloud Function ID sample_rate: Audio sample rate in Hz. If not provided, uses the pipeline's rate params: Additional configuration parameters for NVIDIA Riva + + .. deprecated:: 1.0 + Use ``settings=NvidiaSegmentedSTTSettings(...)`` instead. + use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService """ - params = params or NvidiaSegmentedSTTService.InputParams() + if params is not None: + _warn_deprecated_param("params", "NvidiaSegmentedSTTSettings") + + _params = params or NvidiaSegmentedSTTService.InputParams() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=NvidiaSegmentedSTTSettings( - model=model_function_map.get("model_name"), - language=self.language_to_service_language(params.language or Language.EN_US) - or "en-US", - profanity_filter=params.profanity_filter, - automatic_punctuation=params.automatic_punctuation, - verbatim_transcripts=params.verbatim_transcripts, - boosted_lm_words=params.boosted_lm_words, - boosted_lm_score=params.boosted_lm_score, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/nvidia/tts.py b/src/pipecat/services/nvidia/tts.py index 6785e9631..0f7491645 100644 --- a/src/pipecat/services/nvidia/tts.py +++ b/src/pipecat/services/nvidia/tts.py @@ -31,7 +31,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language @@ -68,6 +68,9 @@ class NvidiaTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Riva TTS configuration. + .. deprecated:: 1.0 + Use ``NvidiaTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language code for synthesis. Defaults to US English. quality: Audio quality setting (0-100). Defaults to 20. @@ -81,13 +84,14 @@ class NvidiaTTSService(TTSService): *, api_key: str, server: str = "grpc.nvcf.nvidia.com:443", - voice_id: str = "Magpie-Multilingual.EN-US.Aria", + voice_id: Optional[str] = None, sample_rate: Optional[int] = None, model_function_map: Mapping[str, str] = { "function_id": "877104f7-e885-42b9-8de8-f6e4c6303969", "model_name": "magpie-tts-multilingual", }, params: Optional[InputParams] = None, + settings: Optional[NvidiaTTSSettings] = None, use_ssl: bool = True, **kwargs, ): @@ -96,23 +100,42 @@ class NvidiaTTSService(TTSService): Args: api_key: NVIDIA API key for authentication. server: gRPC server endpoint. Defaults to NVIDIA's cloud endpoint. - voice_id: Voice model identifier. Defaults to multilingual Ray voice. + voice_id: Voice model identifier. Defaults to multilingual Aria voice. + + .. deprecated:: 1.0 + Use ``settings=NvidiaTTSSettings(voice=...)`` instead. + sample_rate: Audio sample rate. If None, uses service default. model_function_map: Dictionary containing function_id and model_name for the TTS model. params: Additional configuration parameters for TTS synthesis. + + .. deprecated:: 1.0 + Use ``settings=NvidiaTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. use_ssl: Whether to use SSL for the NVIDIA Riva server. Defaults to True. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or NvidiaTTSService.InputParams() + 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() + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=NvidiaTTSSettings( - model=model_function_map.get("model_name"), - voice=voice_id, - language=params.language, - quality=params.quality, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/ollama/llm.py b/src/pipecat/services/ollama/llm.py index 04f22bbae..ecae3fc95 100644 --- a/src/pipecat/services/ollama/llm.py +++ b/src/pipecat/services/ollama/llm.py @@ -6,9 +6,13 @@ """OLLama LLM service implementation for Pipecat AI framework.""" +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class OLLamaLLMService(OpenAILLMService): @@ -19,17 +23,35 @@ class OLLamaLLMService(OpenAILLMService): """ def __init__( - self, *, model: str = "llama2", base_url: str = "http://localhost:11434/v1", **kwargs + self, + *, + model: Optional[str] = None, + base_url: str = "http://localhost:11434/v1", + settings: Optional[OpenAILLMSettings] = None, + **kwargs, ): """Initialize OLLama LLM service. Args: model: The OLLama model to use. Defaults to "llama2". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for the OLLama API endpoint. Defaults to "http://localhost:11434/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(model=model, base_url=base_url, api_key="ollama", **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "llama2") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(base_url=base_url, api_key="ollama", settings=default_settings, **kwargs) def create_client(self, base_url=None, **kwargs): """Create OpenAI-compatible client for Ollama. diff --git a/src/pipecat/services/openai/base_llm.py b/src/pipecat/services/openai/base_llm.py index ed012d0df..22cf89897 100644 --- a/src/pipecat/services/openai/base_llm.py +++ b/src/pipecat/services/openai/base_llm.py @@ -75,6 +75,10 @@ class BaseOpenAILLMService(LLMService): class InputParams(BaseModel): """Input parameters for OpenAI model configuration. + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(...)`` instead of + ``params=InputParams(...)``. + Parameters: frequency_penalty: Penalty for frequent tokens (-2.0 to 2.0). presence_penalty: Penalty for new tokens (-2.0 to 2.0). @@ -108,13 +112,14 @@ class BaseOpenAILLMService(LLMService): def __init__( self, *, - model: str, + model: Optional[str] = None, api_key=None, base_url=None, organization=None, project=None, default_headers: Optional[Mapping[str, str]] = None, params: Optional[InputParams] = None, + settings: Optional[OpenAILLMSettings] = None, retry_timeout_secs: Optional[float] = 5.0, retry_on_timeout: Optional[bool] = False, system_instruction: Optional[str] = None, @@ -124,35 +129,50 @@ class BaseOpenAILLMService(LLMService): Args: model: The OpenAI model name to use (e.g., "gpt-4.1", "gpt-4o"). + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_key: OpenAI API key. If None, uses environment variable. base_url: Custom base URL for OpenAI API. If None, uses default. organization: OpenAI organization ID. project: OpenAI project ID. default_headers: Additional HTTP headers to include in requests. params: Input parameters for model configuration and behavior. + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. retry_timeout_secs: Request timeout in seconds. Defaults to 5.0 seconds. retry_on_timeout: Whether to retry the request once if it times out. system_instruction: Optional system instruction to prepend to messages. **kwargs: Additional arguments passed to the parent LLMService. """ - params = params or BaseOpenAILLMService.InputParams() + _params = params or BaseOpenAILLMService.InputParams() + + 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, + top_k=None, + max_tokens=_params.max_tokens, + max_completion_tokens=_params.max_completion_tokens, + service_tier=_params.service_tier, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + extra=_params.extra if isinstance(_params.extra, dict) else {}, + ) + + if settings is not None: + default_settings.apply_update(settings) super().__init__( - settings=OpenAILLMSettings( - model=model, - frequency_penalty=params.frequency_penalty, - presence_penalty=params.presence_penalty, - seed=params.seed, - temperature=params.temperature, - top_p=params.top_p, - top_k=None, - max_tokens=params.max_tokens, - max_completion_tokens=params.max_completion_tokens, - service_tier=params.service_tier, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - extra=params.extra if isinstance(params.extra, dict) else {}, - ), + settings=default_settings, **kwargs, ) self._retry_timeout_secs = retry_timeout_secs diff --git a/src/pipecat/services/openai/image.py b/src/pipecat/services/openai/image.py index f35a5ded8..2dc66876c 100644 --- a/src/pipecat/services/openai/image.py +++ b/src/pipecat/services/openai/image.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( URLImageRawFrame, ) from pipecat.services.image_service import ImageGenService -from pipecat.services.settings import ImageGenSettings +from pipecat.services.settings import ImageGenSettings, _warn_deprecated_param @dataclass @@ -52,7 +52,8 @@ class OpenAIImageGenService(ImageGenService): base_url: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, image_size: Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"], - model: str = "dall-e-3", + model: Optional[str] = None, + settings: Optional[OpenAIImageGenSettings] = None, ): """Initialize the OpenAI image generation service. @@ -62,8 +63,21 @@ class OpenAIImageGenService(ImageGenService): aiohttp_session: HTTP session for downloading generated images. image_size: Target size for generated images. model: DALL-E model to use for generation. Defaults to "dall-e-3". + + .. deprecated:: 1.0 + Use ``settings=OpenAIImageGenSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. """ - super().__init__(settings=OpenAIImageGenSettings(model=model)) + if model is not None: + _warn_deprecated_param("model", "OpenAIImageGenSettings", "model") + + default_settings = OpenAIImageGenSettings(model=model or "dall-e-3") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings) self._image_size = image_size self._client = AsyncOpenAI(api_key=api_key, base_url=base_url) self._aiohttp_session = aiohttp_session diff --git a/src/pipecat/services/openai/llm.py b/src/pipecat/services/openai/llm.py index b760b0d6e..c259987a8 100644 --- a/src/pipecat/services/openai/llm.py +++ b/src/pipecat/services/openai/llm.py @@ -23,7 +23,8 @@ from pipecat.processors.aggregators.llm_response import ( LLMUserContextAggregator, ) from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext -from pipecat.services.openai.base_llm import BaseOpenAILLMService +from pipecat.services.openai.base_llm import BaseOpenAILLMService, OpenAILLMSettings +from pipecat.services.settings import _warn_deprecated_param @dataclass @@ -72,18 +73,53 @@ class OpenAILLMService(BaseOpenAILLMService): def __init__( self, *, - model: str = "gpt-4.1", + model: Optional[str] = None, params: Optional[BaseOpenAILLMService.InputParams] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize OpenAI LLM service. Args: model: The OpenAI model name to use. Defaults to "gpt-4.1". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + params: Input parameters for model configuration. + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent BaseOpenAILLMService. """ - super().__init__(model=model, params=params, **kwargs) + 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() + 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, + top_k=None, + max_tokens=_params.max_tokens, + max_completion_tokens=_params.max_completion_tokens, + service_tier=_params.service_tier, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + extra=_params.extra if isinstance(_params.extra, dict) else {}, + ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) def create_context_aggregator( self, diff --git a/src/pipecat/services/openai/realtime/llm.py b/src/pipecat/services/openai/realtime/llm.py index 07b6aa82b..d6e7a71bd 100644 --- a/src/pipecat/services/openai/realtime/llm.py +++ b/src/pipecat/services/openai/realtime/llm.py @@ -59,7 +59,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt @@ -121,9 +121,10 @@ class OpenAIRealtimeLLMService(LLMService): self, *, api_key: str, - model: str = "gpt-realtime-1.5", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[OpenAIRealtimeLLMSettings] = None, start_audio_paused: bool = False, start_video_paused: bool = False, video_frame_detail: str = "auto", @@ -134,14 +135,25 @@ class OpenAIRealtimeLLMService(LLMService): Args: api_key: OpenAI API key for authentication. - model: OpenAI model name. Defaults to "gpt-realtime". + model: OpenAI model name. + + .. deprecated:: + Use ``settings=OpenAIRealtimeLLMSettings(model=...)`` instead. + This is a connection-level parameter set via the WebSocket URL query parameter and cannot be changed during the session. base_url: WebSocket base URL for the realtime API. Defaults to "wss://api.openai.com/v1/realtime". session_properties: Configuration properties for the realtime session. + + .. deprecated:: + Use ``settings=OpenAIRealtimeLLMSettings(session_properties=...)`` + instead. + These are session-level settings that can be updated during the session (except for voice and model). If None, uses default SessionProperties. + settings: Realtime LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. start_audio_paused: Whether to start with audio input paused. Defaults to False. start_video_paused: Whether to start with video input paused. Defaults to False. video_frame_detail: Detail level for video processing. Can be "auto", "low", or "high". @@ -156,6 +168,12 @@ 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 @@ -168,24 +186,28 @@ class OpenAIRealtimeLLMService(LLMService): stacklevel=2, ) + default_settings = OpenAIRealtimeLLMSettings( + model=model or "gpt-realtime-1.5", + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + session_properties=session_properties or events.SessionProperties(), + ) + if settings is not None: + default_settings.apply_update(settings) + # Build WebSocket URL with model query parameter # Source: https://platform.openai.com/docs/guides/realtime-websocket - full_url = f"{base_url}?model={model}" + full_url = f"{base_url}?model={default_settings.model}" super().__init__( base_url=full_url, - settings=OpenAIRealtimeLLMSettings( - model=model, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/openai/stt.py b/src/pipecat/services/openai/stt.py index 32895f8b5..be933cd9a 100644 --- a/src/pipecat/services/openai/stt.py +++ b/src/pipecat/services/openai/stt.py @@ -35,10 +35,14 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import OPENAI_REALTIME_TTFS_P99, OPENAI_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_stt @@ -61,30 +65,40 @@ class OpenAISTTService(BaseWhisperSTTService): def __init__( self, *, - model: str = "gpt-4o-transcribe", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, language: Optional[Language] = Language.EN, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[BaseWhisperSTTSettings] = None, ttfs_p99_latency: Optional[float] = OPENAI_TTFS_P99, **kwargs, ): """Initialize OpenAI STT service. Args: - model: Model to use — either gpt-4o or Whisper. Defaults to "gpt-4o-transcribe". + model: Model to use — either gpt-4o or Whisper. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(model=...)`` instead. + api_key: OpenAI API key. Defaults to None. base_url: API base URL. Defaults to None. language: Language of the audio input. Defaults to English. prompt: Optional text to guide the model's style or continue a previous segment. temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to BaseWhisperSTTService. """ + if model is not None: + _warn_deprecated_param("model", "BaseWhisperSTTSettings", "model") + super().__init__( - model=model, + model=model or "gpt-4o-transcribe", api_key=api_key, base_url=base_url, language=language, @@ -94,6 +108,9 @@ class OpenAISTTService(BaseWhisperSTTService): **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 @@ -175,13 +192,14 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): self, *, api_key: str, - model: str = "gpt-4o-transcribe", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", language: Optional[Language] = Language.EN, prompt: Optional[str] = None, turn_detection: Optional[Union[dict, Literal[False]]] = False, noise_reduction: Optional[Literal["near_field", "far_field"]] = None, should_interrupt: bool = True, + settings: Optional[OpenAIRealtimeSTTSettings] = None, ttfs_p99_latency: Optional[float] = OPENAI_REALTIME_TTFS_P99, **kwargs, ): @@ -191,7 +209,10 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): api_key: OpenAI API key for authentication. model: Transcription model. Supported values are ``"gpt-4o-transcribe"`` and ``"gpt-4o-mini-transcribe"``. - Defaults to ``"gpt-4o-transcribe"``. + + .. deprecated:: 1.0 + Use ``settings=OpenAIRealtimeSTTSettings(model=...)`` instead. + base_url: WebSocket base URL for the Realtime API. Defaults to ``"wss://api.openai.com/v1/realtime"``. language: Language of the audio input. Defaults to English. @@ -208,6 +229,8 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): should_interrupt: Whether to interrupt bot output when speech is detected by server-side VAD. Only applies when turn detection is enabled. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to parent @@ -219,13 +242,20 @@ class OpenAIRealtimeSTTService(WebsocketSTTService): "Install it with: pip install pipecat-ai[openai]" ) + if model is not None: + _warn_deprecated_param("model", "OpenAIRealtimeSTTSettings", "model") + + default_settings = OpenAIRealtimeSTTSettings( + model=model or "gpt-4o-transcribe", + language=language, + prompt=prompt, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( ttfs_p99_latency=ttfs_p99_latency, - settings=OpenAIRealtimeSTTSettings( - model=model, - language=language, - prompt=prompt, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/openai/tts.py b/src/pipecat/services/openai/tts.py index f95d79134..965b8faf7 100644 --- a/src/pipecat/services/openai/tts.py +++ b/src/pipecat/services/openai/tts.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -90,6 +90,9 @@ class OpenAITTSService(TTSService): class InputParams(BaseModel): """Input parameters for OpenAI TTS configuration. + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(...)`` instead. + Parameters: instructions: Instructions to guide voice synthesis behavior. speed: Voice speed control (0.25 to 4.0, default 1.0). @@ -103,12 +106,13 @@ class OpenAITTSService(TTSService): *, api_key: Optional[str] = None, base_url: Optional[str] = None, - voice: str = "alloy", - model: str = "gpt-4o-mini-tts", + voice: Optional[str] = None, + model: Optional[str] = None, sample_rate: Optional[int] = None, instructions: Optional[str] = None, speed: Optional[float] = None, params: Optional[InputParams] = None, + settings: Optional[OpenAITTSSettings] = None, **kwargs, ): """Initialize OpenAI TTS service. @@ -117,40 +121,69 @@ class OpenAITTSService(TTSService): api_key: OpenAI API key for authentication. If None, uses environment variable. base_url: Custom base URL for OpenAI API. If None, uses default. voice: Voice ID to use for synthesis. Defaults to "alloy". + + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(voice=...)`` instead. + model: TTS model to use. Defaults to "gpt-4o-mini-tts". + + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(model=...)`` instead. + sample_rate: Output audio sample rate in Hz. If None, uses OpenAI's default 24kHz. instructions: Optional instructions to guide voice synthesis behavior. - speed: Voice speed control (0.25 to 4.0, default 1.0). - params: Optional synthesis controls (acting instructions, speed, ...). - **kwargs: Additional keyword arguments passed to TTSService. - .. deprecated:: 0.0.91 - The `instructions` and `speed` parameters are deprecated, use `InputParams` instead. + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(instructions=...)`` instead. + + speed: Voice speed control (0.25 to 4.0, default 1.0). + + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(speed=...)`` instead. + + params: Optional synthesis controls (acting instructions, speed, ...). + + .. deprecated:: 1.0 + Use ``settings=OpenAITTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. + **kwargs: Additional keyword arguments passed to TTSService. """ + if 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." ) - if instructions or speed: - import warnings - with warnings.catch_warnings(): - warnings.simplefilter("always") - warnings.warn( - "The `instructions` and `speed` parameters are deprecated, use `InputParams` instead.", - DeprecationWarning, - stacklevel=2, - ) + _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 + + default_settings = OpenAITTSSettings( + model=model or "gpt-4o-mini-tts", + voice=voice or "alloy", + language=None, + instructions=_instructions, + speed=_speed, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=OpenAITTSSettings( - model=model, - voice=voice, - instructions=params.instructions if params else instructions, - speed=params.speed if params else speed, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/openai_realtime_beta/openai.py b/src/pipecat/services/openai_realtime_beta/openai.py index c912ed45c..cb660ce72 100644 --- a/src/pipecat/services/openai_realtime_beta/openai.py +++ b/src/pipecat/services/openai_realtime_beta/openai.py @@ -54,7 +54,7 @@ from pipecat.processors.aggregators.openai_llm_context import ( from pipecat.processors.frame_processor import FrameDirection from pipecat.services.llm_service import FunctionCallFromLLM, LLMService from pipecat.services.openai.llm import OpenAIContextAggregatorPair -from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param from pipecat.transcriptions.language import Language from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt @@ -126,9 +126,10 @@ class OpenAIRealtimeBetaLLMService(LLMService): self, *, api_key: str, - model: str = "gpt-4o-realtime-preview-2025-06-03", + model: Optional[str] = None, base_url: str = "wss://api.openai.com/v1/realtime", session_properties: Optional[events.SessionProperties] = None, + settings: Optional[OpenAIRealtimeBetaLLMSettings] = None, start_audio_paused: bool = False, send_transcription_frames: bool = True, **kwargs, @@ -137,11 +138,22 @@ class OpenAIRealtimeBetaLLMService(LLMService): Args: api_key: OpenAI API key for authentication. - model: OpenAI model name. Defaults to "gpt-4o-realtime-preview-2025-06-03". + model: OpenAI model name. + + .. deprecated:: + Use ``settings=OpenAIRealtimeBetaLLMSettings(model=...)`` instead. + base_url: WebSocket base URL for the realtime API. Defaults to "wss://api.openai.com/v1/realtime". session_properties: Configuration properties for the realtime session. + + .. deprecated:: + Use ``settings=OpenAIRealtimeBetaLLMSettings(session_properties=...)`` + instead. + If None, uses default SessionProperties. + settings: Realtime Beta LLM settings. If provided together with deprecated + top-level parameters, the ``settings`` values take precedence. start_audio_paused: Whether to start with audio input paused. Defaults to False. send_transcription_frames: Whether to emit transcription frames. Defaults to True. **kwargs: Additional arguments passed to parent LLMService. @@ -155,22 +167,33 @@ class OpenAIRealtimeBetaLLMService(LLMService): stacklevel=2, ) - full_url = f"{base_url}?model={model}" + 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" + ) + + default_settings = OpenAIRealtimeBetaLLMSettings( + model=model or "gpt-4o-realtime-preview-2025-06-03", + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + session_properties=session_properties or events.SessionProperties(), + ) + if settings is not None: + default_settings.apply_update(settings) + + full_url = f"{base_url}?model={default_settings.model}" super().__init__( base_url=full_url, - settings=OpenAIRealtimeBetaLLMSettings( - model=model, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - session_properties=session_properties or events.SessionProperties(), - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/openpipe/llm.py b/src/pipecat/services/openpipe/llm.py index fa53c1554..524eff860 100644 --- a/src/pipecat/services/openpipe/llm.py +++ b/src/pipecat/services/openpipe/llm.py @@ -15,7 +15,9 @@ from typing import Dict, Optional from loguru import logger from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param try: from openpipe import AsyncOpenAI as OpenPipeAI @@ -36,31 +38,45 @@ class OpenPipeLLMService(OpenAILLMService): def __init__( self, *, - model: str = "gpt-4.1", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, openpipe_api_key: Optional[str] = None, openpipe_base_url: str = "https://app.openpipe.ai/api/v1", tags: Optional[Dict[str, str]] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize OpenPipe LLM service. Args: model: The model name to use. Defaults to "gpt-4.1". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + api_key: OpenAI API key for authentication. If None, reads from environment. base_url: Custom OpenAI API endpoint URL. Uses default if None. openpipe_api_key: OpenPipe API key for enhanced features. If None, reads from environment. openpipe_base_url: OpenPipe API endpoint URL. Defaults to "https://app.openpipe.ai/api/v1". tags: Optional dictionary of tags to apply to all requests for tracking. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent OpenAILLMService. """ + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "gpt-4.1") + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - model=model, api_key=api_key, base_url=base_url, openpipe_api_key=openpipe_api_key, openpipe_base_url=openpipe_base_url, + settings=default_settings, **kwargs, ) self._tags = tags diff --git a/src/pipecat/services/openrouter/llm.py b/src/pipecat/services/openrouter/llm.py index c33fda2fc..9b202c04d 100644 --- a/src/pipecat/services/openrouter/llm.py +++ b/src/pipecat/services/openrouter/llm.py @@ -14,7 +14,9 @@ from typing import Any, Dict, Optional from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class OpenRouterLLMService(OpenAILLMService): @@ -28,8 +30,9 @@ class OpenRouterLLMService(OpenAILLMService): self, *, api_key: Optional[str] = None, - model: str = "openai/gpt-4o-2024-11-20", + model: Optional[str] = None, base_url: str = "https://openrouter.ai/api/v1", + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the OpenRouter LLM service. @@ -38,13 +41,26 @@ class OpenRouterLLMService(OpenAILLMService): api_key: The API key for accessing OpenRouter's API. If None, will attempt to read from environment variables. model: The model identifier to use. Defaults to "openai/gpt-4o-2024-11-20". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for OpenRouter API. Defaults to "https://openrouter.ai/api/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "openai/gpt-4o-2024-11-20") + if settings is not None: + default_settings.apply_update(settings) + super().__init__( api_key=api_key, base_url=base_url, - model=model, + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/perplexity/llm.py b/src/pipecat/services/perplexity/llm.py index e03bace8d..b00f9e974 100644 --- a/src/pipecat/services/perplexity/llm.py +++ b/src/pipecat/services/perplexity/llm.py @@ -11,11 +11,15 @@ an OpenAI-compatible interface. It handles Perplexity's unique token usage reporting patterns while maintaining compatibility with the Pipecat framework. """ +from typing import Optional + from pipecat.adapters.services.open_ai_adapter import OpenAILLMInvocationParams from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class PerplexityLLMService(OpenAILLMService): @@ -31,7 +35,8 @@ class PerplexityLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.perplexity.ai", - model: str = "sonar", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Perplexity LLM service. @@ -40,9 +45,22 @@ class PerplexityLLMService(OpenAILLMService): api_key: The API key for accessing Perplexity's API. base_url: The base URL for Perplexity's API. Defaults to "https://api.perplexity.ai". model: The model identifier to use. Defaults to "sonar". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "sonar") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) # Counters for accumulating token usage metrics self._prompt_tokens = 0 self._completion_tokens = 0 diff --git a/src/pipecat/services/piper/tts.py b/src/pipecat/services/piper/tts.py index c4831b839..559824b49 100644 --- a/src/pipecat/services/piper/tts.py +++ b/src/pipecat/services/piper/tts.py @@ -20,7 +20,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import TTSSettings +from pipecat.services.settings import TTSSettings, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -53,41 +53,56 @@ class PiperTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, download_dir: Optional[Path] = None, force_redownload: bool = False, use_cuda: bool = False, + settings: Optional[PiperTTSSettings] = None, **kwargs, ): """Initialize the Piper TTS service. Args: voice_id: Piper voice model identifier (e.g. `en_US-ryan-high`). + + .. deprecated:: 1.0 + Use ``settings=PiperTTSSettings(voice=...)`` instead. + download_dir: Directory for storing voice model files. Defaults to the current working directory. force_redownload: Re-download the voice model even if it already exists. use_cuda: Use CUDA for GPU-accelerated inference. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent `TTSService`. """ + if voice_id is not None: + _warn_deprecated_param("voice_id", "PiperTTSSettings", "voice") + + default_settings = PiperTTSSettings(model=None, voice=voice_id, language=None) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=PiperTTSSettings(model=None, voice=voice_id, language=None), + settings=default_settings, **kwargs, ) download_dir = download_dir or Path.cwd() - model_file = f"{voice_id}.onnx" + _voice = self._settings.voice + model_file = f"{_voice}.onnx" model_path = Path(download_dir) / model_file if not model_path.exists(): - logger.debug(f"Downloading Piper '{voice_id}' model") - download_voice(voice_id, download_dir, force_redownload=force_redownload) + logger.debug(f"Downloading Piper '{_voice}' model") + download_voice(_voice, download_dir, force_redownload=force_redownload) - logger.debug(f"Loading Piper '{voice_id}' model from {model_path}") + logger.debug(f"Loading Piper '{_voice}' model from {model_path}") self._voice = PiperVoice.load(model_path, use_cuda=use_cuda) - logger.debug(f"Loaded Piper '{voice_id}' model") + logger.debug(f"Loaded Piper '{_voice}' model") def can_generate_metrics(self) -> bool: """Check if this service can generate processing metrics. @@ -190,6 +205,7 @@ class PiperHttpTTSService(TTSService): base_url: str, aiohttp_session: aiohttp.ClientSession, voice_id: Optional[str] = None, + settings: Optional[PiperHttpTTSSettings] = None, **kwargs, ): """Initialize the Piper TTS service. @@ -198,10 +214,23 @@ class PiperHttpTTSService(TTSService): base_url: Base URL for the Piper TTS HTTP server. aiohttp_session: aiohttp ClientSession for making HTTP requests. voice_id: Piper voice model identifier (e.g. `en_US-ryan-high`). + + .. deprecated:: 1.0 + Use ``settings=PiperHttpTTSSettings(voice=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent TTSService. """ + if voice_id is not None: + _warn_deprecated_param("voice_id", "PiperHttpTTSSettings", "voice") + + default_settings = PiperHttpTTSSettings(model=None, voice=voice_id, language=None) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=PiperHttpTTSSettings(model=None, voice=voice_id, language=None), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/qwen/llm.py b/src/pipecat/services/qwen/llm.py index 6b58faea2..132924662 100644 --- a/src/pipecat/services/qwen/llm.py +++ b/src/pipecat/services/qwen/llm.py @@ -6,9 +6,13 @@ """Qwen LLM service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class QwenLLMService(OpenAILLMService): @@ -23,7 +27,8 @@ class QwenLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", - model: str = "qwen-plus", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize the Qwen LLM service. @@ -32,10 +37,23 @@ class QwenLLMService(OpenAILLMService): api_key: The API key for accessing Qwen's API (DashScope API key). base_url: Base URL for Qwen API. Defaults to "https://dashscope-intl.aliyuncs.com/compatible-mode/v1". model: The model identifier to use. Defaults to "qwen-plus". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) - logger.info(f"Initialized Qwen LLM service with model: {model}") + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "qwen-plus") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) + logger.info(f"Initialized Qwen LLM service with model: {self._settings.model}") def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Qwen API endpoint. diff --git a/src/pipecat/services/resembleai/tts.py b/src/pipecat/services/resembleai/tts.py index 1c2953b72..148dacde2 100644 --- a/src/pipecat/services/resembleai/tts.py +++ b/src/pipecat/services/resembleai/tts.py @@ -23,7 +23,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import AudioContextTTSService from pipecat.utils.tracing.service_decorators import traced_tts @@ -70,11 +70,12 @@ class ResembleAITTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://websocket.cluster.resemble.ai/stream", precision: Optional[str] = "PCM_16", output_format: Optional[str] = "wav", sample_rate: Optional[int] = 22050, + settings: Optional[ResembleAITTSSettings] = None, **kwargs, ): """Initialize the Resemble AI TTS service. @@ -82,24 +83,37 @@ class ResembleAITTSService(AudioContextTTSService): Args: api_key: Resemble AI API key for authentication. voice_id: Voice UUID to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=ResembleAITTSSettings(voice=...)`` instead. + url: WebSocket URL for Resemble AI TTS API. precision: PCM bit depth (PCM_32, PCM_24, PCM_16, or MULAW). output_format: Audio format (wav or mp3). sample_rate: Audio sample rate (8000, 16000, 22050, 32000, or 44100). Defaults to 22050. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to the parent service. """ + if voice_id is not None: + _warn_deprecated_param("voice_id", "ResembleAITTSSettings", "voice") + + default_settings = ResembleAITTSSettings( + model=None, + voice=voice_id, + language=None, + precision=precision, + output_format=output_format, + resemble_sample_rate=sample_rate, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, reuse_context_id_within_turn=False, supports_word_timestamps=True, - settings=ResembleAITTSSettings( - model=None, - voice=voice_id, - language=None, - precision=precision, - output_format=output_format, - resemble_sample_rate=sample_rate, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/rime/tts.py b/src/pipecat/services/rime/tts.py index 944ff4e58..a44b738d1 100644 --- a/src/pipecat/services/rime/tts.py +++ b/src/pipecat/services/rime/tts.py @@ -31,7 +31,7 @@ from pipecat.frames.frames import ( TTSStoppedFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import ( AudioContextTTSService, InterruptibleTTSService, @@ -144,6 +144,9 @@ class RimeTTSService(AudioContextTTSService): class InputParams(BaseModel): """Configuration parameters for Rime TTS service. + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. segment: Text segmentation mode ("immediate", "bySentence", "never"). @@ -176,11 +179,12 @@ class RimeTTSService(AudioContextTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://users-ws.rime.ai/ws3", - model: str = "arcana", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeTTSSettings] = None, text_aggregator: Optional[BaseTextAggregator] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, aggregate_sentences: Optional[bool] = None, @@ -191,10 +195,24 @@ class RimeTTSService(AudioContextTTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(voice=...)`` instead. + url: Rime websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. text_aggregator: Custom text aggregator for processing input text. .. deprecated:: 0.0.95 @@ -208,8 +226,40 @@ 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() + _params = params or RimeTTSService.InputParams() + + default_settings = RimeTTSSettings( + model=model or "arcana", + voice=voice_id, + audioFormat="pcm", + samplingRate=0, # updated in start() + language=self.language_to_service_language(_params.language) + if _params.language + else None, + segment=_params.segment, + inlineSpeedAlpha=None, # Not applicable here + speedAlpha=_params.speed_alpha, + # Arcana params + repetition_penalty=_params.repetition_penalty, + temperature=_params.temperature, + top_p=_params.top_p, + # Mistv2 params + reduceLatency=_params.reduce_latency, + pauseBetweenBrackets=_params.pause_between_brackets, + phonemizeBetweenBrackets=_params.phonemize_between_brackets, + noTextNormalization=_params.no_text_normalization, + saveOovs=_params.save_oovs, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( text_aggregation_mode=text_aggregation_mode, @@ -220,28 +270,7 @@ class RimeTTSService(AudioContextTTSService): supports_word_timestamps=True, append_trailing_space=True, sample_rate=sample_rate, - settings=RimeTTSSettings( - model=model, - voice=voice_id, - audioFormat="pcm", - samplingRate=0, # updated in start() - language=self.language_to_service_language(params.language) - if params.language - else None, - segment=params.segment, - inlineSpeedAlpha=None, # Not applicable here - speedAlpha=params.speed_alpha, - # Arcana params - repetition_penalty=params.repetition_penalty, - temperature=params.temperature, - top_p=params.top_p, - # Mistv2 params - reduceLatency=params.reduce_latency, - pauseBetweenBrackets=params.pause_between_brackets, - phonemizeBetweenBrackets=params.phonemize_between_brackets, - noTextNormalization=params.no_text_normalization, - saveOovs=params.save_oovs, - ), + settings=default_settings, **kwargs, ) @@ -628,6 +657,9 @@ class RimeHttpTTSService(TTSService): class InputParams(BaseModel): """Configuration parameters for Rime HTTP TTS service. + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(...)`` instead. + Parameters: language: Language for synthesis. Defaults to English. pause_between_brackets: Whether to add pauses between bracketed content. @@ -648,11 +680,12 @@ class RimeHttpTTSService(TTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, - model: str = "mistv2", + model: Optional[str] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeTTSSettings] = None, **kwargs, ): """Initialize Rime HTTP TTS service. @@ -660,36 +693,61 @@ class RimeHttpTTSService(TTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. model: Model ID to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(model=...)`` instead. + sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=RimeTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ - params = params or RimeHttpTTSService.InputParams() + 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() + + default_settings = RimeTTSSettings( + model=model or "mistv2", + language=self.language_to_service_language(_params.language) + if _params.language + else "eng", + audioFormat="pcm", + samplingRate=0, + segment=None, + speedAlpha=_params.speed_alpha, + reduceLatency=_params.reduce_latency, + pauseBetweenBrackets=_params.pause_between_brackets, + phonemizeBetweenBrackets=_params.phonemize_between_brackets, + noTextNormalization=None, + saveOovs=None, + inlineSpeedAlpha=_params.inline_speed_alpha if _params.inline_speed_alpha else None, + repetition_penalty=None, + temperature=None, + top_p=None, + voice=voice_id, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=RimeTTSSettings( - model=model, - language=self.language_to_service_language(params.language) - if params.language - else "eng", - audioFormat="pcm", - samplingRate=0, - segment=None, - speedAlpha=params.speed_alpha, - reduceLatency=params.reduce_latency, - pauseBetweenBrackets=params.pause_between_brackets, - phonemizeBetweenBrackets=params.phonemize_between_brackets, - noTextNormalization=None, - saveOovs=None, - inlineSpeedAlpha=params.inline_speed_alpha if params.inline_speed_alpha else None, - repetition_penalty=None, - temperature=None, - top_p=None, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -810,6 +868,9 @@ class RimeNonJsonTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Configuration parameters for Rime Non-JSON WebSocket TTS service. + .. deprecated:: 1.0 + Use ``settings=RimeNonJsonTTSSettings(...)`` instead. + Args: language: Language for synthesis. Defaults to English. segment: Text segmentation mode ("immediate", "bySentence", "never"). @@ -830,12 +891,13 @@ class RimeNonJsonTTSService(InterruptibleTTSService): self, *, api_key: str, - voice_id: str, + voice_id: Optional[str] = None, url: str = "wss://users.rime.ai/ws", - model: str = "arcana", + model: Optional[str] = None, audio_format: str = "pcm", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[RimeNonJsonTTSSettings] = None, aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, **kwargs, @@ -845,11 +907,25 @@ class RimeNonJsonTTSService(InterruptibleTTSService): Args: api_key: Rime API key for authentication. voice_id: ID of the voice to use. + + .. deprecated:: 1.0 + Use ``settings=RimeNonJsonTTSSettings(voice=...)`` instead. + url: Rime websocket API endpoint. model: Model ID to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=RimeNonJsonTTSSettings(model=...)`` instead. + audio_format: Audio format to use. sample_rate: Audio sample rate in Hz. params: Additional configuration parameters. + + .. deprecated:: 1.0 + Use ``settings=RimeNonJsonTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. aggregate_sentences: Deprecated. Use text_aggregation_mode instead. .. deprecated:: 0.0.104 @@ -860,7 +936,31 @@ class RimeNonJsonTTSService(InterruptibleTTSService): text_aggregation_mode: How to aggregate text before synthesis. **kwargs: Additional arguments passed to parent class. """ - params = params or RimeNonJsonTTSService.InputParams() + 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() + + default_settings = RimeNonJsonTTSSettings( + voice=voice_id, + model=model or "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, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, aggregate_sentences=aggregate_sentences, @@ -868,26 +968,14 @@ class RimeNonJsonTTSService(InterruptibleTTSService): push_stop_frames=True, pause_frame_processing=True, append_trailing_space=True, - settings=RimeNonJsonTTSSettings( - voice=voice_id, - model=model, - audioFormat=audio_format, - samplingRate=sample_rate, - language=self.language_to_service_language(params.language) - if params.language - else None, - segment=params.segment, - repetition_penalty=params.repetition_penalty, - temperature=params.temperature, - top_p=params.top_p, - ), + settings=default_settings, **kwargs, ) 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.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 016e1740d..23d415598 100644 --- a/src/pipecat/services/sambanova/llm.py +++ b/src/pipecat/services/sambanova/llm.py @@ -21,7 +21,9 @@ from pipecat.metrics.metrics import LLMTokenUsage from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext from pipecat.services.llm_service import FunctionCallFromLLM +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param from pipecat.utils.tracing.service_decorators import traced_llm @@ -36,8 +38,9 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore self, *, api_key: str, - model: str = "Llama-4-Maverick-17B-128E-Instruct", + model: Optional[str] = None, base_url: str = "https://api.sambanova.ai/v1", + settings: Optional[OpenAILLMSettings] = None, **kwargs: Dict[Any, Any], ) -> None: """Initialize SambaNova LLM service. @@ -45,10 +48,23 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore Args: api_key: The API key for accessing SambaNova API. model: The model identifier to use. Defaults to "Llama-4-Maverick-17B-128E-Instruct". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + base_url: The base URL for SambaNova API. Defaults to "https://api.sambanova.ai/v1". + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings(model=model or "Llama-4-Maverick-17B-128E-Instruct") + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client( self, diff --git a/src/pipecat/services/sambanova/stt.py b/src/pipecat/services/sambanova/stt.py index f313f0d7b..4e3c9e01d 100644 --- a/src/pipecat/services/sambanova/stt.py +++ b/src/pipecat/services/sambanova/stt.py @@ -10,8 +10,13 @@ from typing import Any, Optional from loguru import logger +from pipecat.services.settings import _warn_deprecated_param from pipecat.services.stt_latency import SAMBANOVA_TTFS_P99 -from pipecat.services.whisper.base_stt import BaseWhisperSTTService, Transcription +from pipecat.services.whisper.base_stt import ( + BaseWhisperSTTService, + BaseWhisperSTTSettings, + Transcription, +) from pipecat.transcriptions.language import Language @@ -25,35 +30,75 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore def __init__( self, *, - model: str = "Whisper-Large-v3", + model: Optional[str] = None, api_key: Optional[str] = None, base_url: str = "https://api.sambanova.ai/v1", - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, + settings: Optional[BaseWhisperSTTSettings] = None, ttfs_p99_latency: Optional[float] = SAMBANOVA_TTFS_P99, **kwargs: Any, ) -> None: """Initialize SambaNova STT service. Args: - model: Whisper model to use. Defaults to "Whisper-Large-v3". + model: Whisper model to use. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(model=...)`` instead. + api_key: SambaNova API key. Defaults to None. base_url: API base URL. Defaults to "https://api.sambanova.ai/v1". - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Optional sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(prompt=...)`` instead. + + temperature: Optional sampling temperature between 0 and 1. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to `pipecat.services.whisper.base_stt.BaseWhisperSTTService`. """ - super().__init__( + 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. + default_settings = BaseWhisperSTTSettings( model=model, - api_key=api_key, + language=self.language_to_service_language(language), base_url=base_url, - language=language, prompt=prompt, temperature=temperature, + ) + 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, ) diff --git a/src/pipecat/services/sarvam/stt.py b/src/pipecat/services/sarvam/stt.py index e368ceb02..b3ac41470 100644 --- a/src/pipecat/services/sarvam/stt.py +++ b/src/pipecat/services/sarvam/stt.py @@ -32,7 +32,13 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.sarvam._sdk import sdk_headers -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, is_given +from pipecat.services.settings import ( + NOT_GIVEN, + STTSettings, + _NotGiven, + _warn_deprecated_param, + is_given, +) from pipecat.services.stt_latency import SARVAM_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -171,6 +177,9 @@ class SarvamSTTService(STTService): class InputParams(BaseModel): """Configuration parameters for Sarvam STT service. + .. deprecated:: 1.0 + Use ``settings=SarvamSTTSettings(...)`` instead. + Parameters: language: Target language for transcription. - saarika:v2.5: Defaults to "unknown" (auto-detect supported) @@ -194,10 +203,11 @@ class SarvamSTTService(STTService): self, *, api_key: str, - model: str = "saarika:v2.5", + model: Optional[str] = None, sample_rate: Optional[int] = None, input_audio_codec: str = "wav", params: Optional[InputParams] = None, + settings: Optional[SarvamSTTSettings] = None, ttfs_p99_latency: Optional[float] = SARVAM_TTFS_P99, keepalive_timeout: Optional[float] = None, keepalive_interval: float = 5.0, @@ -207,13 +217,20 @@ class SarvamSTTService(STTService): Args: api_key: Sarvam API key for authentication. - model: Sarvam model to use for transcription. Allowed values: - - "saarika:v2.5": Standard STT model - - "saaras:v2.5": STT-Translate model (auto-detects language, supports prompts) - - "saaras:v3": Advanced STT model (supports mode) + model: Sarvam model to use for transcription. + + .. deprecated:: 1.0 + Use ``settings=SarvamSTTSettings(model=...)`` instead. + sample_rate: Audio sample rate. Defaults to 16000 if not specified. input_audio_codec: Audio codec/format of the input file. Defaults to "wav". params: Configuration parameters for Sarvam STT service. + + .. deprecated:: 1.0 + Use ``settings=SarvamSTTSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark keepalive_timeout: Seconds of no audio before sending silence to keep the @@ -221,7 +238,13 @@ class SarvamSTTService(STTService): keepalive_interval: Seconds between idle checks when keepalive is enabled. **kwargs: Additional arguments passed to the parent STTService. """ - params = params or SarvamSTTService.InputParams() + if model is not None: + _warn_deprecated_param("model", "SarvamSTTSettings", "model") + if params is not None: + _warn_deprecated_param("params", "SarvamSTTSettings") + + model = model or "saarika:v2.5" + _params = params or SarvamSTTService.InputParams() # Get model configuration (validates model exists) if model not in MODEL_CONFIGS: @@ -231,31 +254,35 @@ class SarvamSTTService(STTService): self._config = MODEL_CONFIGS[model] # Validate parameters against model capabilities - if params.prompt is not None and not self._config.supports_prompt: + 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: + 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 _params.language is not None and not self._config.supports_language: raise ValueError( f"Model '{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 + 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) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=keepalive_timeout, keepalive_interval=keepalive_interval, - settings=SarvamSTTSettings( - model=model, - language=params.language, - prompt=params.prompt, - mode=mode, - vad_signals=params.vad_signals, - high_vad_sensitivity=params.high_vad_sensitivity, - ), + settings=default_settings, **kwargs, ) @@ -274,7 +301,7 @@ class SarvamSTTService(STTService): self._socket_client = None self._receive_task = None - if params.vad_signals: + if _params.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 c18933407..4d125dfc9 100644 --- a/src/pipecat/services/sarvam/tts.py +++ b/src/pipecat/services/sarvam/tts.py @@ -62,7 +62,7 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection from pipecat.services.sarvam._sdk import sdk_headers -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import InterruptibleTTSService, TextAggregationMode, TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -376,6 +376,9 @@ class SarvamHttpTTSService(TTSService): class InputParams(BaseModel): """Input parameters for Sarvam TTS configuration. + .. deprecated:: 1.0 + Use ``SarvamHttpTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: language: Language for synthesis. Defaults to English (India). pitch: Voice pitch adjustment (-0.75 to 0.75). Defaults to 0.0. @@ -428,10 +431,11 @@ class SarvamHttpTTSService(TTSService): api_key: str, aiohttp_session: aiohttp.ClientSession, voice_id: Optional[str] = None, - model: str = "bulbul:v2", + model: Optional[str] = None, base_url: str = "https://api.sarvam.ai", sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[SarvamHttpTTSSettings] = None, **kwargs, ): """Initialize the Sarvam TTS service. @@ -440,15 +444,38 @@ class SarvamHttpTTSService(TTSService): api_key: Sarvam AI API subscription key. aiohttp_session: Shared aiohttp session for making requests. voice_id: Speaker voice ID. If None, uses model-appropriate default. + + .. deprecated:: 1.0 + Use ``settings=SarvamHttpTTSSettings(voice=...)`` instead. + model: TTS model to use. Options: - "bulbul:v2" (default): Standard model with pitch/loudness support - "bulbul:v3-beta": Advanced model with temperature control + + .. deprecated:: 1.0 + Use ``settings=SarvamHttpTTSSettings(model=...)`` instead. + base_url: Sarvam AI API base URL. Defaults to "https://api.sarvam.ai". sample_rate: Audio sample rate in Hz (8000, 16000, 22050, 24000). If None, uses model-specific default. params: Additional voice and preprocessing parameters. If None, uses defaults. + + .. deprecated:: 1.0 + Use ``settings=SarvamHttpTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + 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") + + model = model or "bulbul:v2" + # Get model configuration (validates model exists) if model not in TTS_MODEL_CONFIGS: allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) @@ -460,39 +487,39 @@ class SarvamHttpTTSService(TTSService): if sample_rate is None: sample_rate = self._config.default_sample_rate - params = params or SarvamHttpTTSService.InputParams() + _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 # Validate and clamp pace to model's valid range - pace = params.pace + pace = _params.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 = 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) + super().__init__( sample_rate=sample_rate, - settings=SarvamHttpTTSSettings( - language=( - self.language_to_service_language(params.language) - if params.language - else "en-IN" - ), - enable_preprocessing=( - True - if self._config.preprocessing_always_enabled - else params.enable_preprocessing - ), - pace=pace, - pitch=None, - loudness=None, - temperature=None, - model=model, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -502,18 +529,18 @@ class SarvamHttpTTSService(TTSService): # Add parameters based on model support if self._config.supports_pitch: - self._settings.pitch = params.pitch - elif params.pitch != 0.0: + 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: + 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: + 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: @@ -697,6 +724,9 @@ class SarvamTTSService(InterruptibleTTSService): class InputParams(BaseModel): """Configuration parameters for Sarvam TTS WebSocket service. + .. deprecated:: 1.0 + Use ``SarvamTTSSettings`` directly via the ``settings`` parameter instead. + Parameters: pitch: Voice pitch adjustment (-0.75 to 0.75). Defaults to 0.0. **Note:** Only supported for bulbul:v2. Ignored for v3 models. @@ -782,13 +812,14 @@ class SarvamTTSService(InterruptibleTTSService): self, *, api_key: str, - model: str = "bulbul:v2", + model: Optional[str] = None, voice_id: Optional[str] = None, url: str = "wss://api.sarvam.ai/text-to-speech/ws", aggregate_sentences: Optional[bool] = None, text_aggregation_mode: Optional[TextAggregationMode] = None, sample_rate: Optional[int] = None, params: Optional[InputParams] = None, + settings: Optional[SarvamTTSSettings] = None, **kwargs, ): """Initialize the Sarvam TTS service with voice and transport configuration. @@ -798,7 +829,15 @@ class SarvamTTSService(InterruptibleTTSService): model: TTS model to use. Options: - "bulbul:v2" (default): Standard model with pitch/loudness support - "bulbul:v3-beta": Advanced model with temperature control + + .. deprecated:: 1.0 + Use ``settings=SarvamTTSSettings(model=...)`` instead. + voice_id: Speaker voice ID. If None, uses model-appropriate default. + + .. deprecated:: 1.0 + Use ``settings=SarvamTTSSettings(voice=...)`` instead. + url: WebSocket URL for the TTS backend (default production URL). aggregate_sentences: Deprecated. Use text_aggregation_mode instead. @@ -809,10 +848,25 @@ class SarvamTTSService(InterruptibleTTSService): sample_rate: Output audio sample rate in Hz (8000, 16000, 22050, 24000). If None, uses model-specific default. params: Optional input parameters to override defaults. + + .. deprecated:: 1.0 + Use ``settings=SarvamTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Arguments forwarded to InterruptibleTTSService. See https://docs.sarvam.ai/api-reference-docs/text-to-speech/stream """ + 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") + + model = model or "bulbul:v2" + # Get model configuration (validates model exists) if model not in TTS_MODEL_CONFIGS: allowed = ", ".join(sorted(TTS_MODEL_CONFIGS.keys())) @@ -828,15 +882,37 @@ class SarvamTTSService(InterruptibleTTSService): if voice_id is None: voice_id = self._config.default_speaker - params = params or SarvamTTSService.InputParams() + _params = params or SarvamTTSService.InputParams() # Validate and clamp pace to model's valid range - pace = params.pace + pace = _params.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 = 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) + # Initialize parent class first super().__init__( aggregate_sentences=aggregate_sentences, @@ -845,29 +921,7 @@ class SarvamTTSService(InterruptibleTTSService): pause_frame_processing=True, push_stop_frames=True, sample_rate=sample_rate, - settings=SarvamTTSSettings( - language=( - self.language_to_service_language(params.language) - if params.language - else "en-IN" - ), - speech_sample_rate=str(sample_rate), - enable_preprocessing=( - True - if self._config.preprocessing_always_enabled - else params.enable_preprocessing - ), - min_buffer_size=params.min_buffer_size, - max_chunk_length=params.max_chunk_length, - output_audio_codec=params.output_audio_codec, - output_audio_bitrate=params.output_audio_bitrate, - pace=pace, - pitch=None, - loudness=None, - temperature=None, - model=model, - voice=voice_id, - ), + settings=default_settings, **kwargs, ) @@ -877,18 +931,18 @@ class SarvamTTSService(InterruptibleTTSService): # Add parameters based on model support if self._config.supports_pitch: - self._settings.pitch = params.pitch - elif params.pitch != 0.0: + 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: + 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: + self._settings.temperature = _params.temperature + elif _params.temperature != 0.6: logger.warning(f"temperature parameter is ignored for {model}") self._receive_task = None diff --git a/src/pipecat/services/settings.py b/src/pipecat/services/settings.py index 5d215273f..546104b9a 100644 --- a/src/pipecat/services/settings.py +++ b/src/pipecat/services/settings.py @@ -37,6 +37,7 @@ Key helpers: from __future__ import annotations import copy +import warnings from dataclasses import dataclass, field, fields from typing import TYPE_CHECKING, Any, ClassVar, Dict, Mapping, Optional, Type, TypeVar @@ -47,6 +48,45 @@ from pipecat.transcriptions.language import Language if TYPE_CHECKING: from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig + +# --------------------------------------------------------------------------- +# Deprecation helper +# --------------------------------------------------------------------------- + + +def _warn_deprecated_param( + param_name: str, + settings_class_name: str, + settings_field: str | None = None, + stacklevel: int = 3, +): + """Emit DeprecationWarning for a deprecated init parameter. + + Args: + param_name: Name of the deprecated parameter. + settings_class_name: Name of 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). + """ + if settings_field: + msg = ( + f"The `{param_name}` parameter is deprecated. " + f"Use `settings={settings_class_name}({settings_field}=...)` instead. " + f"If both are provided, `settings` takes precedence." + ) + else: + msg = ( + f"The `{param_name}` parameter is deprecated. " + f"Use `settings={settings_class_name}(...)` instead. " + f"If both are provided, `settings` takes precedence." + ) + with warnings.catch_warnings(): + warnings.simplefilter("always") + warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel) + + # --------------------------------------------------------------------------- # NOT_GIVEN sentinel # --------------------------------------------------------------------------- diff --git a/src/pipecat/services/soniox/stt.py b/src/pipecat/services/soniox/stt.py index 32cbee1f4..84c437f36 100644 --- a/src/pipecat/services/soniox/stt.py +++ b/src/pipecat/services/soniox/stt.py @@ -24,7 +24,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import SONIOX_TTFS_P99 from pipecat.services.stt_service import WebsocketSTTService from pipecat.transcriptions.language import Language @@ -79,6 +79,9 @@ class SonioxContextObject(BaseModel): class SonioxInputParams(BaseModel): """Real-time transcription settings. + .. deprecated:: 1.0 + Use ``settings=SonioxSTTSettings(...)`` instead. + See Soniox WebSocket API documentation for more details: https://soniox.com/docs/speech-to-text/api-reference/websocket-api#configuration-parameters @@ -183,8 +186,10 @@ class SonioxSTTService(WebsocketSTTService): api_key: str, url: str = "wss://stt-rt.soniox.com/transcribe-websocket", sample_rate: Optional[int] = None, + model: Optional[str] = None, params: Optional[SonioxInputParams] = None, vad_force_turn_endpoint: bool = True, + settings: Optional[SonioxSTTSettings] = None, ttfs_p99_latency: Optional[float] = SONIOX_TTFS_P99, **kwargs, ): @@ -194,33 +199,53 @@ class SonioxSTTService(WebsocketSTTService): api_key: Soniox API key. url: Soniox WebSocket API URL. sample_rate: Audio sample rate. + model: Soniox model to use for transcription. + + .. deprecated:: 1.0 + Use ``settings=SonioxSTTSettings(model=...)`` instead. + params: Additional configuration parameters, such as language hints, context and speaker diarization. + + .. deprecated:: 1.0 + Use ``settings=SonioxSTTSettings(...)`` instead. + vad_force_turn_endpoint: Listen to `VADUserStoppedSpeakingFrame` to send finalize message to Soniox. If disabled, Soniox will detect the end of the speech. Defaults to True. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to the STTService. """ - params = params or SonioxInputParams() + 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() + + default_settings = SonioxSTTSettings( + model=model or _params.model, + language=None, + audio_format=_params.audio_format, + num_channels=_params.num_channels, + language_hints=_params.language_hints, + language_hints_strict=_params.language_hints_strict, + context=_params.context, + enable_speaker_diarization=_params.enable_speaker_diarization, + enable_language_identification=_params.enable_language_identification, + client_reference_id=_params.client_reference_id, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, keepalive_timeout=1, keepalive_interval=5, - settings=SonioxSTTSettings( - model=params.model, - language=None, - audio_format=params.audio_format, - num_channels=params.num_channels, - language_hints=params.language_hints, - language_hints_strict=params.language_hints_strict, - context=params.context, - enable_speaker_diarization=params.enable_speaker_diarization, - enable_language_identification=params.enable_language_identification, - client_reference_id=params.client_reference_id, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/speechmatics/stt.py b/src/pipecat/services/speechmatics/stt.py index bdeb3b249..a0ca19f74 100644 --- a/src/pipecat/services/speechmatics/stt.py +++ b/src/pipecat/services/speechmatics/stt.py @@ -33,7 +33,7 @@ from pipecat.frames.frames import ( VADUserStoppedSpeakingFrame, ) from pipecat.processors.frame_processor import FrameDirection -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import SPEECHMATICS_TTFS_P99 from pipecat.services.stt_service import STTService from pipecat.transcriptions.language import Language, resolve_language @@ -381,6 +381,7 @@ class SpeechmaticsSTTService(STTService): sample_rate: int | None = None, params: InputParams | None = None, should_interrupt: bool = True, + settings: SpeechmaticsSTTSettings | None = None, ttfs_p99_latency: float | None = SPEECHMATICS_TTFS_P99, **kwargs, ): @@ -392,8 +393,14 @@ class SpeechmaticsSTTService(STTService): base_url: Base URL for Speechmatics API. Uses environment variable `SPEECHMATICS_RT_URL` or defaults to `wss://eu2.rt.speechmatics.com/v2`. sample_rate: Optional audio sample rate in Hz. - params: Optional[InputParams]: Input parameters for the service. + params: Input parameters for the service. + + .. deprecated:: 1.0 + Use ``settings=SpeechmaticsSTTSettings(...)`` instead. + should_interrupt: Determine whether the bot should be interrupted when Speechmatics turn_detection_mode is configured to detect user speech. + settings: Runtime-updatable settings. When provided alongside deprecated + ``params``, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to STTService. @@ -410,6 +417,9 @@ 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 @@ -426,7 +436,7 @@ class SpeechmaticsSTTService(STTService): speaker_passive_format = params.speaker_passive_format or speaker_active_format # Settings — seeded from InputParams - settings = SpeechmaticsSTTSettings( + default_settings = SpeechmaticsSTTSettings( model=None, # Will be resolved from operating_point after config is built language=params.language, domain=params.domain, @@ -455,13 +465,16 @@ class SpeechmaticsSTTService(STTService): # Build SDK config from settings, then resolve model from operating_point self._client: VoiceAgentClient | None = None - self._config: VoiceAgentConfig = self._build_config(settings) - settings.model = self._config.operating_point.value + self._config: VoiceAgentConfig = self._build_config(default_settings) + default_settings.model = self._config.operating_point.value + + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, - settings=settings, + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/speechmatics/tts.py b/src/pipecat/services/speechmatics/tts.py index 1ddb895aa..e1260fbe2 100644 --- a/src/pipecat/services/speechmatics/tts.py +++ b/src/pipecat/services/speechmatics/tts.py @@ -22,7 +22,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.utils.network import exponential_backoff_time from pipecat.utils.tracing.service_decorators import traced_tts @@ -62,6 +62,9 @@ class SpeechmaticsTTSService(TTSService): class InputParams(BaseModel): """Optional input parameters for Speechmatics TTS configuration. + .. deprecated:: 1.0 + Use ``settings=SpeechmaticsTTSSettings(...)`` instead. + Parameters: max_retries: Maximum number of retries for TTS requests. Defaults to 5. """ @@ -73,10 +76,11 @@ class SpeechmaticsTTSService(TTSService): *, api_key: str, base_url: str = "https://preview.tts.speechmatics.com", - voice_id: str = "sarah", + voice_id: Optional[str] = None, aiohttp_session: aiohttp.ClientSession, sample_rate: Optional[int] = SPEECHMATICS_SAMPLE_RATE, params: Optional[InputParams] = None, + settings: Optional[SpeechmaticsTTSSettings] = None, **kwargs, ): """Initialize the Speechmatics TTS service. @@ -85,26 +89,45 @@ class SpeechmaticsTTSService(TTSService): api_key: Speechmatics API key for authentication. base_url: Base URL for Speechmatics TTS API. voice_id: Voice model to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=SpeechmaticsTTSSettings(voice=...)`` instead. + aiohttp_session: Shared aiohttp session for HTTP requests. sample_rate: Audio sample rate in Hz. - params: Optional[InputParams]: Input parameters for the service. + params: Input parameters for the service. + + .. deprecated:: 1.0 + Use ``settings=SpeechmaticsTTSSettings(...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + 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() + _params = params or SpeechmaticsTTSService.InputParams() + + default_settings = SpeechmaticsTTSSettings( + model=None, + voice=voice_id or "sarah", + language=None, + max_retries=_params.max_retries, + ) + if settings is not None: + default_settings.apply_update(settings) super().__init__( sample_rate=sample_rate, - settings=SpeechmaticsTTSSettings( - model=None, - voice=voice_id, - language=None, - max_retries=params.max_retries, - ), + settings=default_settings, **kwargs, ) diff --git a/src/pipecat/services/tavus/video.py b/src/pipecat/services/tavus/video.py index 8c63ff354..e6725fac1 100644 --- a/src/pipecat/services/tavus/video.py +++ b/src/pipecat/services/tavus/video.py @@ -34,6 +34,7 @@ from pipecat.frames.frames import ( ) from pipecat.processors.frame_processor import FrameDirection, FrameProcessorSetup from pipecat.services.ai_service import AIService +from pipecat.services.settings import ServiceSettings from pipecat.transports.tavus.transport import TavusCallbacks, TavusParams, TavusTransportClient @@ -57,6 +58,7 @@ class TavusVideoService(AIService): replica_id: str, persona_id: str = "pipecat-stream", session: aiohttp.ClientSession, + settings: Optional[ServiceSettings] = None, **kwargs, ) -> None: """Initialize the Tavus video service. @@ -66,9 +68,15 @@ class TavusVideoService(AIService): replica_id: ID of the Tavus voice replica to use for speech synthesis. persona_id: ID of the Tavus persona. Defaults to "pipecat-stream" for Pipecat TTS voice. session: Async HTTP session used for communication with Tavus. + settings: Runtime-updatable settings. Tavus has no model concept, so this + is primarily used for the ``extra`` dict. **kwargs: Additional arguments passed to the parent AIService class. """ - super().__init__(**kwargs) + default_settings = ServiceSettings(model=None) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(settings=default_settings, **kwargs) self._api_key = api_key self._session = session self._replica_id = replica_id diff --git a/src/pipecat/services/together/llm.py b/src/pipecat/services/together/llm.py index 277e8bc9c..b1cb4ffea 100644 --- a/src/pipecat/services/together/llm.py +++ b/src/pipecat/services/together/llm.py @@ -6,9 +6,13 @@ """Together.ai LLM service implementation using OpenAI-compatible interface.""" +from typing import Optional + from loguru import logger +from pipecat.services.openai.base_llm import OpenAILLMSettings from pipecat.services.openai.llm import OpenAILLMService +from pipecat.services.settings import _warn_deprecated_param class TogetherLLMService(OpenAILLMService): @@ -23,7 +27,8 @@ class TogetherLLMService(OpenAILLMService): *, api_key: str, base_url: str = "https://api.together.xyz/v1", - model: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", + model: Optional[str] = None, + settings: Optional[OpenAILLMSettings] = None, **kwargs, ): """Initialize Together.ai LLM service. @@ -32,9 +37,24 @@ class TogetherLLMService(OpenAILLMService): api_key: The API key for accessing Together.ai's API. base_url: The base URL for Together.ai API. Defaults to "https://api.together.xyz/v1". model: The model identifier to use. Defaults to "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo". + + .. deprecated:: 1.0 + Use ``settings=OpenAILLMSettings(model=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional keyword arguments passed to OpenAILLMService. """ - super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) + if model is not None: + _warn_deprecated_param("model", "OpenAILLMSettings", "model") + + default_settings = OpenAILLMSettings( + model=model or "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo" + ) + if settings is not None: + default_settings.apply_update(settings) + + super().__init__(api_key=api_key, base_url=base_url, settings=default_settings, **kwargs) def create_client(self, api_key=None, base_url=None, **kwargs): """Create OpenAI-compatible client for Together.ai API endpoint. diff --git a/src/pipecat/services/ultravox/llm.py b/src/pipecat/services/ultravox/llm.py index 07c3c34fe..933930152 100644 --- a/src/pipecat/services/ultravox/llm.py +++ b/src/pipecat/services/ultravox/llm.py @@ -172,32 +172,38 @@ class UltravoxRealtimeLLMService(LLMService): self, *, params: Union[AgentInputParams, OneShotInputParams, JoinUrlInputParams], + settings: Optional[UltravoxRealtimeLLMSettings] = None, one_shot_selected_tools: Optional[ToolsSchema] = None, **kwargs, ): """Initialize the Ultravox Realtime LLM service. Args: - api_key: Ultravox API key for authentication. params: Configuration parameters for the model. + settings: Ultravox Realtime LLM settings. If provided, the ``settings`` + values take precedence over default values. one_shot_selected_tools: ToolsSchema for tools to use with this call. May only be set with OneShotInputParams. **kwargs: Additional arguments passed to parent LLMService. """ + default_settings = UltravoxRealtimeLLMSettings( + model=None, + temperature=None, + max_tokens=None, + top_p=None, + top_k=None, + frequency_penalty=None, + presence_penalty=None, + seed=None, + filter_incomplete_user_turns=False, + user_turn_completion_config=None, + output_medium=None, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=UltravoxRealtimeLLMSettings( - model=None, - temperature=None, - max_tokens=None, - top_p=None, - top_k=None, - frequency_penalty=None, - presence_penalty=None, - seed=None, - filter_incomplete_user_turns=False, - user_turn_completion_config=None, - output_medium=None, - ), + settings=default_settings, **kwargs, ) self._params = params diff --git a/src/pipecat/services/whisper/base_stt.py b/src/pipecat/services/whisper/base_stt.py index cf3342f4b..e254a7929 100644 --- a/src/pipecat/services/whisper/base_stt.py +++ b/src/pipecat/services/whisper/base_stt.py @@ -18,7 +18,7 @@ from openai import AsyncOpenAI from openai.types.audio import Transcription from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_latency import WHISPER_TTFS_P99 from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language @@ -129,13 +129,14 @@ class BaseWhisperSTTService(SegmentedSTTService): def __init__( self, *, - model: str, + model: Optional[str] = None, api_key: Optional[str] = None, base_url: Optional[str] = None, - language: Optional[Language] = Language.EN, + language: Optional[Language] = None, prompt: Optional[str] = None, temperature: Optional[float] = None, include_prob_metrics: bool = False, + settings: Optional[BaseWhisperSTTSettings] = None, ttfs_p99_latency: Optional[float] = WHISPER_TTFS_P99, **kwargs, ): @@ -143,33 +144,68 @@ class BaseWhisperSTTService(SegmentedSTTService): Args: model: Name of the Whisper model to use. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(model=...)`` instead. + api_key: Service API key. Defaults to None. base_url: Service API base URL. Defaults to None. - language: Language of the audio input. Defaults to English. + language: Language of the audio input. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(language=...)`` instead. + prompt: Optional text to guide the model's style or continue a previous segment. - temperature: Sampling temperature between 0 and 1. Defaults to 0.0. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(prompt=...)`` instead. + + temperature: Sampling temperature between 0 and 1. + + .. deprecated:: 1.0 + Use ``settings=BaseWhisperSTTSettings(temperature=...)`` instead. + include_prob_metrics: If True, enables probability metrics in API response. Each service implements this differently (see child classes). Defaults to False. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. """ + 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 + + default_settings = BaseWhisperSTTSettings( + model=model, + language=self.language_to_service_language(_language), + base_url=base_url, + prompt=prompt, + temperature=temperature, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( ttfs_p99_latency=ttfs_p99_latency, - settings=BaseWhisperSTTSettings( - model=model, - language=self.language_to_service_language(language or Language.EN), - base_url=base_url, - prompt=prompt, - temperature=temperature, - ), + settings=default_settings, **kwargs, ) self._client = self._create_client(api_key, base_url) self._language = self._settings.language - self._prompt = prompt - self._temperature = temperature + self._prompt = self._settings.prompt if self._settings.prompt else prompt + self._temperature = ( + self._settings.temperature if self._settings.temperature else 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 d386d6ed2..2e0a6156a 100644 --- a/src/pipecat/services/whisper/stt.py +++ b/src/pipecat/services/whisper/stt.py @@ -20,7 +20,7 @@ from loguru import logger from typing_extensions import TYPE_CHECKING, override from pipecat.frames.frames import ErrorFrame, Frame, TranscriptionFrame -from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, STTSettings, _NotGiven, _warn_deprecated_param from pipecat.services.stt_service import SegmentedSTTService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.time import time_now_iso8601 @@ -216,36 +216,80 @@ class WhisperSTTService(SegmentedSTTService): def __init__( self, *, - model: str | Model = Model.DISTIL_MEDIUM_EN, - device: str = "auto", - compute_type: str = "default", - no_speech_prob: float = 0.4, - language: Language = Language.EN, + model: Optional[str | Model] = None, + device: Optional[str] = None, + compute_type: Optional[str] = None, + no_speech_prob: Optional[float] = None, + language: Optional[Language] = None, + settings: Optional[WhisperSTTSettings] = None, **kwargs, ): """Initialize the Whisper STT service. Args: model: The Whisper model to use for transcription. Can be a Model enum or string. + + .. deprecated:: 1.0 + Use ``settings=WhisperSTTSettings(model=...)`` instead. + device: The device to run inference on ('cpu', 'cuda', or 'auto'). + + .. deprecated:: 1.0 + Use ``settings=WhisperSTTSettings(device=...)`` instead. + compute_type: The compute type for inference ('default', 'int8', 'int8_float16', etc.). + + .. deprecated:: 1.0 + Use ``settings=WhisperSTTSettings(compute_type=...)`` instead. + no_speech_prob: Probability threshold for filtering out non-speech segments. + + .. deprecated:: 1.0 + Use ``settings=WhisperSTTSettings(no_speech_prob=...)`` instead. + language: The default language for transcription. + + .. deprecated:: 1.0 + Use ``settings=WhisperSTTSettings(language=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + 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 + + 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, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( - settings=WhisperSTTSettings( - model=model if isinstance(model, str) else model.value, - language=language, - device=device, - compute_type=compute_type, - no_speech_prob=no_speech_prob, - ), + settings=default_settings, **kwargs, ) - self._device: str = device - self._compute_type = compute_type - self._no_speech_prob = no_speech_prob + self._device: str = self._settings.device + self._compute_type = self._settings.compute_type + self._no_speech_prob = self._settings.no_speech_prob self._model: Optional[WhisperModel] = None self._load() @@ -352,36 +396,73 @@ class WhisperSTTServiceMLX(WhisperSTTService): def __init__( self, *, - model: str | MLXModel = MLXModel.TINY, - no_speech_prob: float = 0.6, - language: Language = Language.EN, - temperature: float = 0.0, + model: Optional[str | MLXModel] = None, + no_speech_prob: Optional[float] = None, + language: Optional[Language] = None, + temperature: Optional[float] = None, + settings: Optional[WhisperMLXSTTSettings] = None, **kwargs, ): """Initialize the MLX Whisper STT service. Args: model: The MLX Whisper model to use for transcription. Can be an MLXModel enum or string. + + .. deprecated:: 1.0 + Use ``settings=WhisperMLXSTTSettings(model=...)`` instead. + no_speech_prob: Probability threshold for filtering out non-speech segments. + + .. deprecated:: 1.0 + Use ``settings=WhisperMLXSTTSettings(no_speech_prob=...)`` instead. + language: The default language for transcription. + + .. deprecated:: 1.0 + Use ``settings=WhisperMLXSTTSettings(language=...)`` instead. + temperature: Temperature for sampling. Can be a float or tuple of floats. + + .. deprecated:: 1.0 + Use ``settings=WhisperMLXSTTSettings(temperature=...)`` instead. + + settings: Runtime-updatable settings. When provided alongside deprecated + 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 + + default_settings = WhisperMLXSTTSettings( + model=_model if isinstance(_model, str) else _model.value, + language=_language, + no_speech_prob=_no_speech_prob, + temperature=_temperature, + engine="mlx", + ) + if settings is not None: + default_settings.apply_update(settings) + # Skip WhisperSTTService.__init__ and call its parent directly SegmentedSTTService.__init__( self, - settings=WhisperMLXSTTSettings( - model=model if isinstance(model, str) else model.value, - language=language, - no_speech_prob=no_speech_prob, - temperature=temperature, - engine="mlx", - ), + settings=default_settings, **kwargs, ) - self._no_speech_prob = no_speech_prob - self._temperature = temperature + self._no_speech_prob = self._settings.no_speech_prob + self._temperature = self._settings.temperature # No need to call _load() as MLX Whisper loads models on demand diff --git a/src/pipecat/services/xtts/tts.py b/src/pipecat/services/xtts/tts.py index 8817c09b5..bba95a400 100644 --- a/src/pipecat/services/xtts/tts.py +++ b/src/pipecat/services/xtts/tts.py @@ -25,7 +25,7 @@ from pipecat.frames.frames import ( TTSStartedFrame, TTSStoppedFrame, ) -from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven +from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven, _warn_deprecated_param from pipecat.services.tts_service import TTSService from pipecat.transcriptions.language import Language, resolve_language from pipecat.utils.tracing.service_decorators import traced_tts @@ -94,31 +94,45 @@ class XTTSService(TTSService): def __init__( self, *, - voice_id: str, + voice_id: Optional[str] = None, base_url: str, aiohttp_session: aiohttp.ClientSession, language: Language = Language.EN, sample_rate: Optional[int] = None, + settings: Optional[XTTSTTSSettings] = None, **kwargs, ): """Initialize the XTTS service. Args: voice_id: ID of the voice/speaker to use for synthesis. + + .. deprecated:: 1.0 + Use ``settings=XTTSTTSSettings(voice=...)`` instead. + base_url: Base URL of the XTTS streaming server. aiohttp_session: HTTP session for making requests to the server. language: Language for synthesis. Defaults to English. sample_rate: Audio sample rate. If None, uses default. + settings: Runtime-updatable settings. When provided alongside deprecated + parameters, ``settings`` values take precedence. **kwargs: Additional arguments passed to parent TTSService. """ + if voice_id is not None: + _warn_deprecated_param("voice_id", "XTTSTTSSettings", "voice") + + default_settings = XTTSTTSSettings( + model=None, + voice=voice_id, + language=self.language_to_service_language(language), + base_url=base_url, + ) + if settings is not None: + default_settings.apply_update(settings) + super().__init__( sample_rate=sample_rate, - settings=XTTSTTSSettings( - model=None, - voice=voice_id, - language=self.language_to_service_language(language), - base_url=base_url, - ), + settings=default_settings, **kwargs, ) self._studio_speakers: Optional[Dict[str, Any]] = None