Update LLMs
This commit is contained in:
@@ -75,10 +75,12 @@ class AWSBedrockLLMSettings(LLMSettings):
|
||||
"""Settings for AWS Bedrock LLM services.
|
||||
|
||||
Parameters:
|
||||
stop_sequences: List of strings that stop generation.
|
||||
latency: Performance mode - "standard" or "optimized".
|
||||
additional_model_request_fields: Additional model-specific parameters.
|
||||
"""
|
||||
|
||||
stop_sequences: List[str] | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
latency: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
additional_model_request_fields: Dict[str, Any] | _NotGiven = field(
|
||||
default_factory=lambda: NOT_GIVEN
|
||||
@@ -810,6 +812,10 @@ class AWSBedrockLLMService(LLMService):
|
||||
deprecated parameters and *settings* are provided, *settings*
|
||||
values take precedence.
|
||||
stop_sequences: List of strings that stop generation.
|
||||
|
||||
.. deprecated:: 0.0.105
|
||||
Use ``settings=AWSBedrockLLMSettings(stop_sequences=...)`` instead.
|
||||
|
||||
client_config: Custom boto3 client configuration.
|
||||
retry_timeout_secs: Request timeout in seconds for retry logic.
|
||||
retry_on_timeout: Whether to retry the request once if it times out.
|
||||
@@ -828,6 +834,7 @@ class AWSBedrockLLMService(LLMService):
|
||||
seed=None,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
stop_sequences=None,
|
||||
latency=None,
|
||||
additional_model_request_fields={},
|
||||
)
|
||||
@@ -836,6 +843,9 @@ class AWSBedrockLLMService(LLMService):
|
||||
if model is not None:
|
||||
_warn_deprecated_param("model", AWSBedrockLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if stop_sequences is not None:
|
||||
_warn_deprecated_param("stop_sequences", AWSBedrockLLMSettings, "stop_sequences")
|
||||
default_settings.stop_sequences = stop_sequences
|
||||
|
||||
# 3. Apply params overrides — only if settings not provided
|
||||
if params is not None:
|
||||
@@ -844,6 +854,8 @@ class AWSBedrockLLMService(LLMService):
|
||||
default_settings.max_tokens = params.max_tokens
|
||||
default_settings.temperature = params.temperature
|
||||
default_settings.top_p = params.top_p
|
||||
if params.stop_sequences:
|
||||
default_settings.stop_sequences = params.stop_sequences
|
||||
default_settings.latency = params.latency
|
||||
if isinstance(params.additional_model_request_fields, dict):
|
||||
default_settings.additional_model_request_fields = (
|
||||
@@ -856,14 +868,6 @@ class AWSBedrockLLMService(LLMService):
|
||||
|
||||
super().__init__(settings=default_settings, **kwargs)
|
||||
|
||||
# Handle stop_sequences (not a settings field)
|
||||
if stop_sequences is not None:
|
||||
self._stop_sequences = stop_sequences
|
||||
elif params is not None:
|
||||
self._stop_sequences = params.stop_sequences or []
|
||||
else:
|
||||
self._stop_sequences = []
|
||||
|
||||
# Initialize the AWS Bedrock client
|
||||
if not client_config:
|
||||
client_config = Config(
|
||||
@@ -915,6 +919,8 @@ class AWSBedrockLLMService(LLMService):
|
||||
inference_config["temperature"] = self._settings.temperature
|
||||
if self._settings.top_p is not None:
|
||||
inference_config["topP"] = self._settings.top_p
|
||||
if self._settings.stop_sequences:
|
||||
inference_config["stopSequences"] = self._settings.stop_sequences
|
||||
return inference_config
|
||||
|
||||
async def run_inference(
|
||||
|
||||
@@ -191,12 +191,12 @@ class AWSNovaSonicLLMSettings(LLMSettings):
|
||||
"""Settings for AWS Nova Sonic LLM service.
|
||||
|
||||
Parameters:
|
||||
voice_id: Voice for speech synthesis.
|
||||
voice: Voice identifier for speech synthesis.
|
||||
endpointing_sensitivity: Controls how quickly Nova Sonic decides the
|
||||
user has stopped speaking. Can be "LOW", "MEDIUM", or "HIGH".
|
||||
"""
|
||||
|
||||
voice_id: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
endpointing_sensitivity: str | None | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class AWSNovaSonicLLMService(LLMService):
|
||||
- Nova Sonic (the older model): see https://docs.aws.amazon.com/nova/latest/userguide/available-voices.html.
|
||||
|
||||
.. deprecated::
|
||||
Use ``settings=AWSNovaSonicLLMSettings(voice_id=...)`` instead.
|
||||
Use ``settings=AWSNovaSonicLLMSettings(voice=...)`` instead.
|
||||
|
||||
params: Model parameters for audio configuration and inference.
|
||||
|
||||
@@ -273,7 +273,7 @@ class AWSNovaSonicLLMService(LLMService):
|
||||
# 1. Initialize default_settings with hardcoded defaults
|
||||
default_settings = AWSNovaSonicLLMSettings(
|
||||
model="amazon.nova-2-sonic-v1:0",
|
||||
voice_id="matthew",
|
||||
voice="matthew",
|
||||
temperature=0.7,
|
||||
max_tokens=1024,
|
||||
top_p=0.9,
|
||||
@@ -291,8 +291,8 @@ class AWSNovaSonicLLMService(LLMService):
|
||||
_warn_deprecated_param("model", AWSNovaSonicLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if voice_id != "matthew":
|
||||
_warn_deprecated_param("voice_id", AWSNovaSonicLLMSettings, "voice_id")
|
||||
default_settings.voice_id = voice_id
|
||||
_warn_deprecated_param("voice_id", AWSNovaSonicLLMSettings, "voice")
|
||||
default_settings.voice = voice_id
|
||||
|
||||
# 3. Apply params overrides — only if settings not provided
|
||||
if params is not None:
|
||||
@@ -811,7 +811,7 @@ class AWSNovaSonicLLMService(LLMService):
|
||||
"sampleRateHertz": {self._output_sample_rate},
|
||||
"sampleSizeBits": {self._output_sample_size},
|
||||
"channelCount": {self._output_channel_count},
|
||||
"voiceId": "{self._settings.voice_id}",
|
||||
"voiceId": "{self._settings.voice}",
|
||||
"encoding": "base64",
|
||||
"audioType": "SPEECH"
|
||||
}}{tools_config}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AzureRealtimeLLMService(OpenAIRealtimeLLMService):
|
||||
real-time audio and text communication capabilities as the base OpenAI service.
|
||||
"""
|
||||
|
||||
_settings: AzureRealtimeLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -31,6 +31,8 @@ class CerebrasLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: CerebrasLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -31,6 +31,8 @@ class DeepSeekLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: DeepSeekLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -31,6 +31,8 @@ class FireworksLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: FireworksLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -610,6 +610,7 @@ class GeminiLiveLLMSettings(LLMSettings):
|
||||
"""Settings for Gemini Live LLM services.
|
||||
|
||||
Parameters:
|
||||
voice: TTS voice identifier (e.g. ``"Charon"``).
|
||||
modalities: Response modalities.
|
||||
language: Language for generation.
|
||||
media_resolution: Media resolution setting.
|
||||
@@ -620,6 +621,7 @@ class GeminiLiveLLMSettings(LLMSettings):
|
||||
proactivity: Proactivity configuration.
|
||||
"""
|
||||
|
||||
voice: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
modalities: GeminiModalities | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
language: Language | str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
media_resolution: GeminiMediaResolution | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
|
||||
@@ -680,6 +682,9 @@ class GeminiLiveLLMService(LLMService):
|
||||
Use ``settings=GeminiLiveLLMSettings(model=...)`` instead.
|
||||
|
||||
voice_id: TTS voice identifier. Defaults to "Charon".
|
||||
|
||||
.. deprecated:: 0.0.105
|
||||
Use ``settings=GeminiLiveLLMSettings(voice=...)`` instead.
|
||||
start_audio_paused: Whether to start with audio input paused. Defaults to False.
|
||||
start_video_paused: Whether to start with video input paused. Defaults to False.
|
||||
system_instruction: System prompt for the model. Defaults to None.
|
||||
@@ -712,6 +717,7 @@ class GeminiLiveLLMService(LLMService):
|
||||
# 1. Initialize default_settings with hardcoded defaults
|
||||
default_settings = GeminiLiveLLMSettings(
|
||||
model="models/gemini-2.5-flash-native-audio-preview-12-2025",
|
||||
voice="Charon",
|
||||
frequency_penalty=None,
|
||||
max_tokens=4096,
|
||||
presence_penalty=None,
|
||||
@@ -736,6 +742,9 @@ class GeminiLiveLLMService(LLMService):
|
||||
if model is not None:
|
||||
_warn_deprecated_param("model", GeminiLiveLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if voice_id != "Charon":
|
||||
_warn_deprecated_param("voice_id", GeminiLiveLLMSettings, "voice")
|
||||
default_settings.voice = voice_id
|
||||
|
||||
# 3. Apply params overrides — only if settings not provided
|
||||
if params is not None:
|
||||
@@ -776,7 +785,6 @@ class GeminiLiveLLMService(LLMService):
|
||||
|
||||
self._last_sent_time = 0
|
||||
self._base_url = base_url
|
||||
self._voice_id = voice_id
|
||||
self._language_code = params.language if params is not None else Language.EN_US
|
||||
|
||||
self._system_instruction_from_init = system_instruction
|
||||
@@ -1184,7 +1192,7 @@ class GeminiLiveLLMService(LLMService):
|
||||
response_modalities=[Modality(self._settings.modalities.value)],
|
||||
speech_config=SpeechConfig(
|
||||
voice_config=VoiceConfig(
|
||||
prebuilt_voice_config={"voice_name": self._voice_id}
|
||||
prebuilt_voice_config={"voice_name": self._settings.voice}
|
||||
),
|
||||
language_code=self._settings.language,
|
||||
),
|
||||
|
||||
@@ -57,6 +57,8 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
|
||||
responses, and tool usage.
|
||||
"""
|
||||
|
||||
_settings: GeminiLiveVertexLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -90,6 +92,9 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
|
||||
Use ``settings=GeminiLiveLLMSettings(model=...)`` instead.
|
||||
|
||||
voice_id: TTS voice identifier. Defaults to "Charon".
|
||||
|
||||
.. deprecated:: 0.0.105
|
||||
Use ``settings=GeminiLiveVertexLLMSettings(voice=...)`` instead.
|
||||
start_audio_paused: Whether to start with audio input paused. Defaults to False.
|
||||
start_video_paused: Whether to start with video input paused. Defaults to False.
|
||||
system_instruction: System prompt for the model. Defaults to None.
|
||||
@@ -132,6 +137,7 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
|
||||
# 1. Initialize default_settings with hardcoded defaults
|
||||
default_settings = GeminiLiveVertexLLMSettings(
|
||||
model="google/gemini-live-2.5-flash-native-audio",
|
||||
voice="Charon",
|
||||
frequency_penalty=None,
|
||||
max_tokens=4096,
|
||||
presence_penalty=None,
|
||||
@@ -156,6 +162,9 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
|
||||
if model is not None:
|
||||
_warn_deprecated_param("model", GeminiLiveVertexLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if voice_id != "Charon":
|
||||
_warn_deprecated_param("voice_id", GeminiLiveVertexLLMSettings, "voice")
|
||||
default_settings.voice = voice_id
|
||||
|
||||
# 3. Apply params overrides — only if settings not provided
|
||||
if params is not None:
|
||||
@@ -193,7 +202,6 @@ class GeminiLiveVertexLLMService(GeminiLiveLLMService):
|
||||
# api_key is required by parent class, but actually not used with
|
||||
# Vertex
|
||||
api_key="dummy",
|
||||
voice_id=voice_id,
|
||||
start_audio_paused=start_audio_paused,
|
||||
start_video_paused=start_video_paused,
|
||||
system_instruction=system_instruction,
|
||||
|
||||
@@ -58,6 +58,8 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService):
|
||||
https://ai.google.dev/gemini-api/docs/openai
|
||||
"""
|
||||
|
||||
_settings: GoogleOpenAILLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -59,6 +59,8 @@ class GoogleVertexLLMService(GoogleLLMService):
|
||||
https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference
|
||||
"""
|
||||
|
||||
_settings: GoogleVertexLLMSettings
|
||||
|
||||
class InputParams(GoogleLLMService.InputParams):
|
||||
"""Input parameters specific to Vertex AI.
|
||||
|
||||
|
||||
@@ -86,6 +86,8 @@ class GrokLLMService(OpenAILLMService):
|
||||
processing and reports final totals.
|
||||
"""
|
||||
|
||||
_settings: GrokLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -13,7 +13,7 @@ https://docs.x.ai/docs/guides/voice/agent
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional
|
||||
|
||||
from loguru import logger
|
||||
@@ -56,7 +56,7 @@ from pipecat.processors.aggregators.llm_response_universal import (
|
||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||
from pipecat.processors.frame_processor import FrameDirection
|
||||
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
|
||||
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
|
||||
from pipecat.services.settings import LLMSettings
|
||||
from pipecat.utils.time import time_now_iso8601
|
||||
|
||||
from . import events
|
||||
@@ -88,15 +88,9 @@ class CurrentAudioResponse:
|
||||
|
||||
@dataclass
|
||||
class GrokRealtimeLLMSettings(LLMSettings):
|
||||
"""Settings for Grok Realtime LLM services.
|
||||
"""Settings for Grok Realtime LLM services."""
|
||||
|
||||
Parameters:
|
||||
session_properties: Grok Realtime session configuration.
|
||||
"""
|
||||
|
||||
session_properties: events.SessionProperties | _NotGiven = field(
|
||||
default_factory=lambda: NOT_GIVEN
|
||||
)
|
||||
pass
|
||||
|
||||
|
||||
class GrokRealtimeLLMService(LLMService):
|
||||
@@ -137,19 +131,13 @@ 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.
|
||||
settings: Runtime-updatable settings for this service.
|
||||
start_audio_paused: Whether to start with audio input paused. Defaults to False.
|
||||
**kwargs: Additional arguments passed to parent LLMService.
|
||||
"""
|
||||
@@ -165,17 +153,9 @@ class GrokRealtimeLLMService(LLMService):
|
||||
seed=None,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
session_properties=events.SessionProperties(),
|
||||
)
|
||||
|
||||
# 2. Apply direct init arg overrides (deprecated)
|
||||
if session_properties is not None:
|
||||
_warn_deprecated_param(
|
||||
"session_properties", GrokRealtimeLLMSettings, "session_properties"
|
||||
)
|
||||
default_settings.session_properties = session_properties
|
||||
|
||||
# 4. Apply settings delta (canonical API, always wins)
|
||||
# 2. Apply settings delta (canonical API, always wins)
|
||||
if settings is not None:
|
||||
default_settings.apply_update(settings)
|
||||
|
||||
@@ -187,6 +167,7 @@ class GrokRealtimeLLMService(LLMService):
|
||||
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url
|
||||
self._session_properties = session_properties or events.SessionProperties()
|
||||
|
||||
self._audio_input_paused = start_audio_paused
|
||||
self._websocket = None
|
||||
@@ -235,13 +216,13 @@ class GrokRealtimeLLMService(LLMService):
|
||||
Configured sample rate or None if not manually configured.
|
||||
For PCMU/PCMA formats, returns 8000 Hz (G.711 standard).
|
||||
"""
|
||||
if not self._settings.session_properties.audio:
|
||||
if not self._session_properties.audio:
|
||||
return None
|
||||
|
||||
audio_config = (
|
||||
self._settings.session_properties.audio.input
|
||||
self._session_properties.audio.input
|
||||
if direction == "input"
|
||||
else self._settings.session_properties.audio.output
|
||||
else self._session_properties.audio.output
|
||||
)
|
||||
|
||||
if audio_config and audio_config.format:
|
||||
@@ -271,8 +252,8 @@ class GrokRealtimeLLMService(LLMService):
|
||||
|
||||
def _is_turn_detection_enabled(self) -> bool:
|
||||
"""Check if server-side VAD is enabled."""
|
||||
if self._settings.session_properties.turn_detection:
|
||||
return self._settings.session_properties.turn_detection.type == "server_vad"
|
||||
if self._session_properties.turn_detection:
|
||||
return self._session_properties.turn_detection.type == "server_vad"
|
||||
return False
|
||||
|
||||
async def _handle_interruption(self):
|
||||
@@ -339,7 +320,7 @@ class GrokRealtimeLLMService(LLMService):
|
||||
input_sample_rate: Sample rate for audio input (Hz).
|
||||
output_sample_rate: Sample rate for audio output (Hz).
|
||||
"""
|
||||
props = self._settings.session_properties
|
||||
props = self._session_properties
|
||||
if not props.audio:
|
||||
props.audio = events.AudioConfiguration()
|
||||
if not props.audio.input:
|
||||
@@ -395,7 +376,12 @@ class GrokRealtimeLLMService(LLMService):
|
||||
# directly. The frame.delta path falls through to super, which calls
|
||||
# _update_settings → our override handles the rest.
|
||||
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
|
||||
self._settings.session_properties = events.SessionProperties(**frame.settings)
|
||||
# Capture current audio config before replacing session properties.
|
||||
input_rate = self._get_configured_sample_rate("input")
|
||||
output_rate = self._get_configured_sample_rate("output")
|
||||
self._session_properties = events.SessionProperties(**frame.settings)
|
||||
if input_rate and output_rate:
|
||||
self._ensure_audio_config(input_rate, output_rate)
|
||||
await self._send_session_update()
|
||||
await self.push_frame(frame, direction)
|
||||
return
|
||||
@@ -498,29 +484,14 @@ class GrokRealtimeLLMService(LLMService):
|
||||
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
|
||||
|
||||
async def _update_settings(self, delta):
|
||||
"""Apply a settings delta, sending a session update if needed."""
|
||||
# Capture current sample rates before the update replaces them.
|
||||
input_rate = self._get_configured_sample_rate("input")
|
||||
output_rate = self._get_configured_sample_rate("output")
|
||||
|
||||
"""Apply a settings delta."""
|
||||
changed = await super()._update_settings(delta)
|
||||
|
||||
if "session_properties" in changed:
|
||||
if input_rate and output_rate:
|
||||
self._ensure_audio_config(input_rate, output_rate)
|
||||
else:
|
||||
logger.warning(
|
||||
"Attempting to apply session properties update without configured sample rates. "
|
||||
"Audio configuration may be incomplete."
|
||||
)
|
||||
await self._send_session_update()
|
||||
|
||||
self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"})
|
||||
self._warn_unhandled_updated_settings(changed.keys())
|
||||
return changed
|
||||
|
||||
async def _send_session_update(self):
|
||||
"""Update session settings on the server."""
|
||||
settings = self._settings.session_properties
|
||||
settings = self._session_properties
|
||||
adapter: GrokRealtimeLLMAdapter = self.get_llm_adapter()
|
||||
|
||||
if self._context:
|
||||
|
||||
@@ -30,6 +30,8 @@ class GroqLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: GroqLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -33,6 +33,8 @@ class MistralLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: MistralLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -36,6 +36,8 @@ class NvidiaLLMService(OpenAILLMService):
|
||||
in token usage reporting between NIM (incremental) and OpenAI (final summary).
|
||||
"""
|
||||
|
||||
_settings: NvidiaLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -30,6 +30,8 @@ class OLLamaLLMService(OpenAILLMService):
|
||||
providing a compatible interface for running large language models locally.
|
||||
"""
|
||||
|
||||
_settings: OllamaLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -53,11 +53,9 @@ class OpenAILLMSettings(LLMSettings):
|
||||
|
||||
Parameters:
|
||||
max_completion_tokens: Maximum completion tokens to generate.
|
||||
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
|
||||
"""
|
||||
|
||||
max_completion_tokens: int | _NotGiven = field(default_factory=lambda: _NOT_GIVEN)
|
||||
service_tier: str | _NotGiven = field(default_factory=lambda: _NOT_GIVEN)
|
||||
|
||||
|
||||
class BaseOpenAILLMService(LLMService):
|
||||
@@ -118,6 +116,7 @@ class BaseOpenAILLMService(LLMService):
|
||||
organization=None,
|
||||
project=None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
service_tier: Optional[str] = None,
|
||||
params: Optional[InputParams] = None,
|
||||
settings: Optional[OpenAILLMSettings] = None,
|
||||
retry_timeout_secs: Optional[float] = 5.0,
|
||||
@@ -138,6 +137,7 @@ class BaseOpenAILLMService(LLMService):
|
||||
organization: OpenAI organization ID.
|
||||
project: OpenAI project ID.
|
||||
default_headers: Additional HTTP headers to include in requests.
|
||||
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
|
||||
params: Input parameters for model configuration and behavior.
|
||||
|
||||
.. deprecated:: 0.0.105
|
||||
@@ -161,7 +161,6 @@ class BaseOpenAILLMService(LLMService):
|
||||
top_k=None,
|
||||
max_tokens=NOT_GIVEN,
|
||||
max_completion_tokens=NOT_GIVEN,
|
||||
service_tier=NOT_GIVEN,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
extra={},
|
||||
@@ -180,7 +179,6 @@ class BaseOpenAILLMService(LLMService):
|
||||
default_settings.top_p = params.top_p
|
||||
default_settings.max_tokens = params.max_tokens
|
||||
default_settings.max_completion_tokens = params.max_completion_tokens
|
||||
default_settings.service_tier = params.service_tier
|
||||
if isinstance(params.extra, dict):
|
||||
default_settings.extra = params.extra
|
||||
|
||||
@@ -192,6 +190,7 @@ class BaseOpenAILLMService(LLMService):
|
||||
settings=default_settings,
|
||||
**kwargs,
|
||||
)
|
||||
self._service_tier = service_tier
|
||||
self._retry_timeout_secs = retry_timeout_secs
|
||||
self._retry_on_timeout = retry_on_timeout
|
||||
self._system_instruction = system_instruction
|
||||
@@ -321,7 +320,7 @@ class BaseOpenAILLMService(LLMService):
|
||||
"top_p": self._settings.top_p,
|
||||
"max_tokens": self._settings.max_tokens,
|
||||
"max_completion_tokens": self._settings.max_completion_tokens,
|
||||
"service_tier": self._settings.service_tier,
|
||||
"service_tier": self._service_tier,
|
||||
}
|
||||
|
||||
# Messages, tools, tool_choice
|
||||
|
||||
@@ -76,6 +76,7 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
self,
|
||||
*,
|
||||
model: Optional[str] = None,
|
||||
service_tier: Optional[str] = None,
|
||||
params: Optional[BaseOpenAILLMService.InputParams] = None,
|
||||
settings: Optional[OpenAILLMSettings] = None,
|
||||
**kwargs,
|
||||
@@ -88,6 +89,7 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
.. deprecated:: 0.0.105
|
||||
Use ``settings=OpenAILLMSettings(model=...)`` instead.
|
||||
|
||||
service_tier: Service tier to use (e.g., "auto", "flex", "priority").
|
||||
params: Input parameters for model configuration.
|
||||
|
||||
.. deprecated:: 0.0.105
|
||||
@@ -108,7 +110,6 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
top_k=None,
|
||||
max_tokens=NOT_GIVEN,
|
||||
max_completion_tokens=NOT_GIVEN,
|
||||
service_tier=NOT_GIVEN,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
extra={},
|
||||
@@ -119,6 +120,10 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
_warn_deprecated_param("model", OpenAILLMSettings, "model")
|
||||
default_settings.model = model
|
||||
|
||||
# Handle service_tier from deprecated params
|
||||
if params is not None and not settings and params.service_tier is not NOT_GIVEN:
|
||||
service_tier = service_tier or params.service_tier
|
||||
|
||||
# 3. Apply params overrides — only if settings not provided
|
||||
if params is not None:
|
||||
_warn_deprecated_param("params", OpenAILLMSettings)
|
||||
@@ -130,7 +135,6 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
default_settings.top_p = params.top_p
|
||||
default_settings.max_tokens = params.max_tokens
|
||||
default_settings.max_completion_tokens = params.max_completion_tokens
|
||||
default_settings.service_tier = params.service_tier
|
||||
if isinstance(params.extra, dict):
|
||||
default_settings.extra = params.extra
|
||||
|
||||
@@ -138,7 +142,7 @@ class OpenAILLMService(BaseOpenAILLMService):
|
||||
if settings is not None:
|
||||
default_settings.apply_update(settings)
|
||||
|
||||
super().__init__(settings=default_settings, **kwargs)
|
||||
super().__init__(service_tier=service_tier, settings=default_settings, **kwargs)
|
||||
|
||||
def create_context_aggregator(
|
||||
self,
|
||||
|
||||
@@ -10,7 +10,7 @@ import base64
|
||||
import io
|
||||
import json
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional
|
||||
|
||||
from loguru import logger
|
||||
@@ -59,7 +59,7 @@ from pipecat.processors.aggregators.openai_llm_context import (
|
||||
)
|
||||
from pipecat.processors.frame_processor import FrameDirection
|
||||
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
|
||||
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
|
||||
from pipecat.services.settings import LLMSettings, _warn_deprecated_param
|
||||
from pipecat.transcriptions.language import Language
|
||||
from pipecat.utils.time import time_now_iso8601
|
||||
from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt
|
||||
@@ -93,15 +93,9 @@ class CurrentAudioResponse:
|
||||
|
||||
@dataclass
|
||||
class OpenAIRealtimeLLMSettings(LLMSettings):
|
||||
"""Settings for OpenAI Realtime LLM services.
|
||||
"""Settings for OpenAI Realtime LLM services."""
|
||||
|
||||
Parameters:
|
||||
session_properties: OpenAI Realtime session configuration.
|
||||
"""
|
||||
|
||||
session_properties: events.SessionProperties | _NotGiven = field(
|
||||
default_factory=lambda: NOT_GIVEN
|
||||
)
|
||||
pass
|
||||
|
||||
|
||||
class OpenAIRealtimeLLMService(LLMService):
|
||||
@@ -145,15 +139,8 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
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.
|
||||
If None, uses default SessionProperties.
|
||||
settings: Runtime-updatable settings for this service.
|
||||
start_audio_paused: Whether to start with audio input paused. Defaults to False.
|
||||
start_video_paused: Whether to start with video input paused. Defaults to False.
|
||||
video_frame_detail: Detail level for video processing. Can be "auto", "low", or "high".
|
||||
@@ -192,20 +179,14 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
seed=None,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
session_properties=events.SessionProperties(),
|
||||
)
|
||||
|
||||
# 2. Apply direct init arg overrides (deprecated)
|
||||
if model is not None:
|
||||
_warn_deprecated_param("model", OpenAIRealtimeLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if session_properties is not None:
|
||||
_warn_deprecated_param(
|
||||
"session_properties", OpenAIRealtimeLLMSettings, "session_properties"
|
||||
)
|
||||
default_settings.session_properties = session_properties
|
||||
|
||||
# 4. Apply settings delta (canonical API, always wins)
|
||||
# 3. Apply settings delta (canonical API, always wins)
|
||||
if settings is not None:
|
||||
default_settings.apply_update(settings)
|
||||
|
||||
@@ -220,6 +201,7 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
|
||||
self.api_key = api_key
|
||||
self.base_url = full_url
|
||||
self._session_properties = session_properties or events.SessionProperties()
|
||||
self._audio_input_paused = start_audio_paused
|
||||
self._video_input_paused = start_video_paused
|
||||
self._video_frame_detail = video_frame_detail
|
||||
@@ -282,12 +264,12 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
|
||||
def _is_modality_enabled(self, modality: str) -> bool:
|
||||
"""Check if a specific modality is enabled, "text" or "audio"."""
|
||||
modalities = self._settings.session_properties.output_modalities or ["audio", "text"]
|
||||
modalities = self._session_properties.output_modalities or ["audio", "text"]
|
||||
return modality in modalities
|
||||
|
||||
def _get_enabled_modalities(self) -> list[str]:
|
||||
"""Get the list of enabled modalities."""
|
||||
modalities = self._settings.session_properties.output_modalities or ["audio", "text"]
|
||||
modalities = self._session_properties.output_modalities or ["audio", "text"]
|
||||
# API only supports single modality responses: either ["text"] or ["audio"]
|
||||
if "audio" in modalities:
|
||||
return ["audio"]
|
||||
@@ -360,9 +342,9 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
# None and False are different. Check for False. None means we're using OpenAI's
|
||||
# built-in turn detection defaults.
|
||||
turn_detection_disabled = (
|
||||
self._settings.session_properties.audio
|
||||
and self._settings.session_properties.audio.input
|
||||
and self._settings.session_properties.audio.input.turn_detection is False
|
||||
self._session_properties.audio
|
||||
and self._session_properties.audio.input
|
||||
and self._session_properties.audio.input.turn_detection is False
|
||||
)
|
||||
if turn_detection_disabled:
|
||||
await self.send_client_event(events.InputAudioBufferClearEvent())
|
||||
@@ -382,9 +364,9 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
# None and False are different. Check for False. None means we're using OpenAI's
|
||||
# built-in turn detection defaults.
|
||||
turn_detection_disabled = (
|
||||
self._settings.session_properties.audio
|
||||
and self._settings.session_properties.audio.input
|
||||
and self._settings.session_properties.audio.input.turn_detection is False
|
||||
self._session_properties.audio
|
||||
and self._session_properties.audio.input
|
||||
and self._session_properties.audio.input.turn_detection is False
|
||||
)
|
||||
if turn_detection_disabled:
|
||||
await self.send_client_event(events.InputAudioBufferCommitEvent())
|
||||
@@ -457,7 +439,7 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
# directly. The frame.delta path falls through to super, which calls
|
||||
# _update_settings → our override handles the rest.
|
||||
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
|
||||
self._settings.session_properties = events.SessionProperties(**frame.settings)
|
||||
self._session_properties = events.SessionProperties(**frame.settings)
|
||||
await self._send_session_update()
|
||||
await self.push_frame(frame, direction)
|
||||
return
|
||||
@@ -576,15 +558,13 @@ class OpenAIRealtimeLLMService(LLMService):
|
||||
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
|
||||
|
||||
async def _update_settings(self, delta):
|
||||
"""Apply a settings delta, sending a session update if needed."""
|
||||
"""Apply a settings delta."""
|
||||
changed = await super()._update_settings(delta)
|
||||
if "session_properties" in changed:
|
||||
await self._send_session_update()
|
||||
self._warn_unhandled_updated_settings(changed.keys() - {"session_properties"})
|
||||
self._warn_unhandled_updated_settings(changed.keys())
|
||||
return changed
|
||||
|
||||
async def _send_session_update(self):
|
||||
settings = self._settings.session_properties
|
||||
settings = self._session_properties
|
||||
adapter: OpenAIRealtimeLLMAdapter = self.get_llm_adapter()
|
||||
|
||||
if self._context:
|
||||
|
||||
@@ -42,6 +42,8 @@ class AzureRealtimeBetaLLMService(OpenAIRealtimeBetaLLMService):
|
||||
real-time audio and text communication capabilities as the base OpenAI service.
|
||||
"""
|
||||
|
||||
_settings: AzureRealtimeBetaLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -10,7 +10,7 @@ import base64
|
||||
import json
|
||||
import time
|
||||
import warnings
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
@@ -54,7 +54,7 @@ from pipecat.processors.aggregators.openai_llm_context import (
|
||||
from pipecat.processors.frame_processor import FrameDirection
|
||||
from pipecat.services.llm_service import FunctionCallFromLLM, LLMService
|
||||
from pipecat.services.openai.llm import OpenAIContextAggregatorPair
|
||||
from pipecat.services.settings import NOT_GIVEN, LLMSettings, _NotGiven, _warn_deprecated_param
|
||||
from pipecat.services.settings import LLMSettings, _warn_deprecated_param
|
||||
from pipecat.transcriptions.language import Language
|
||||
from pipecat.utils.time import time_now_iso8601
|
||||
from pipecat.utils.tracing.service_decorators import traced_openai_realtime, traced_stt
|
||||
@@ -94,15 +94,9 @@ class CurrentAudioResponse:
|
||||
|
||||
@dataclass
|
||||
class OpenAIRealtimeBetaLLMSettings(LLMSettings):
|
||||
"""Settings for OpenAI Realtime Beta LLM services.
|
||||
"""Settings for OpenAI Realtime Beta LLM services."""
|
||||
|
||||
Parameters:
|
||||
session_properties: OpenAI Realtime session configuration.
|
||||
"""
|
||||
|
||||
session_properties: events.SessionProperties | _NotGiven = field(
|
||||
default_factory=lambda: NOT_GIVEN
|
||||
)
|
||||
pass
|
||||
|
||||
|
||||
class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
@@ -146,14 +140,8 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
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.
|
||||
settings: Runtime-updatable settings for this service.
|
||||
start_audio_paused: Whether to start with audio input paused. Defaults to False.
|
||||
send_transcription_frames: Whether to emit transcription frames. Defaults to True.
|
||||
**kwargs: Additional arguments passed to parent LLMService.
|
||||
@@ -179,20 +167,13 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
seed=None,
|
||||
filter_incomplete_user_turns=False,
|
||||
user_turn_completion_config=None,
|
||||
session_properties=events.SessionProperties(),
|
||||
)
|
||||
|
||||
# 2. Apply direct init arg overrides (deprecated)
|
||||
if model is not None:
|
||||
_warn_deprecated_param("model", OpenAIRealtimeBetaLLMSettings, "model")
|
||||
default_settings.model = model
|
||||
if session_properties is not None:
|
||||
_warn_deprecated_param(
|
||||
"session_properties", OpenAIRealtimeBetaLLMSettings, "session_properties"
|
||||
)
|
||||
default_settings.session_properties = session_properties
|
||||
|
||||
# 4. Apply settings delta (canonical API, always wins)
|
||||
# 3. Apply settings delta (canonical API, always wins)
|
||||
if settings is not None:
|
||||
default_settings.apply_update(settings)
|
||||
|
||||
@@ -205,6 +186,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
|
||||
self.api_key = api_key
|
||||
self.base_url = full_url
|
||||
self._session_properties = session_properties or events.SessionProperties()
|
||||
self._audio_input_paused = start_audio_paused
|
||||
self._send_transcription_frames = send_transcription_frames
|
||||
self._websocket = None
|
||||
@@ -243,12 +225,12 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
|
||||
def _is_modality_enabled(self, modality: str) -> bool:
|
||||
"""Check if a specific modality is enabled, "text" or "audio"."""
|
||||
modalities = self._settings.session_properties.modalities or ["audio", "text"]
|
||||
modalities = self._session_properties.modalities or ["audio", "text"]
|
||||
return modality in modalities
|
||||
|
||||
def _get_enabled_modalities(self) -> list[str]:
|
||||
"""Get the list of enabled modalities."""
|
||||
return self._settings.session_properties.modalities or ["audio", "text"]
|
||||
return self._session_properties.modalities or ["audio", "text"]
|
||||
|
||||
async def retrieve_conversation_item(self, item_id: str):
|
||||
"""Retrieve a conversation item by ID from the server.
|
||||
@@ -315,7 +297,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
async def _handle_interruption(self):
|
||||
# None and False are different. Check for False. None means we're using OpenAI's
|
||||
# built-in turn detection defaults.
|
||||
if self._settings.session_properties.turn_detection is False:
|
||||
if self._session_properties.turn_detection is False:
|
||||
await self.send_client_event(events.InputAudioBufferClearEvent())
|
||||
await self.send_client_event(events.ResponseCancelEvent())
|
||||
await self._truncate_current_audio_response()
|
||||
@@ -332,7 +314,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
async def _handle_user_stopped_speaking(self, frame):
|
||||
# None and False are different. Check for False. None means we're using OpenAI's
|
||||
# built-in turn detection defaults.
|
||||
if self._settings.session_properties.turn_detection is False:
|
||||
if self._session_properties.turn_detection is False:
|
||||
await self.send_client_event(events.InputAudioBufferCommitEvent())
|
||||
await self.send_client_event(events.ResponseCreateEvent())
|
||||
|
||||
@@ -403,7 +385,7 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
# directly. The frame.delta path falls through to super, which calls
|
||||
# _update_settings → our override handles the rest.
|
||||
if isinstance(frame, LLMUpdateSettingsFrame) and frame.delta is None:
|
||||
self._settings.session_properties = events.SessionProperties(**frame.settings)
|
||||
self._session_properties = events.SessionProperties(**frame.settings)
|
||||
await self._send_session_update()
|
||||
await self.push_frame(frame, direction)
|
||||
return
|
||||
@@ -520,14 +502,13 @@ class OpenAIRealtimeBetaLLMService(LLMService):
|
||||
await self.push_error(error_msg=f"Error sending client event: {e}", exception=e)
|
||||
|
||||
async def _update_settings(self, delta):
|
||||
"""Apply a settings delta, sending a session update if needed."""
|
||||
"""Apply a settings delta."""
|
||||
changed = await super()._update_settings(delta)
|
||||
if "session_properties" in changed:
|
||||
await self._send_session_update()
|
||||
self._warn_unhandled_updated_settings(changed.keys())
|
||||
return changed
|
||||
|
||||
async def _send_session_update(self):
|
||||
settings = self._settings.session_properties
|
||||
settings = self._session_properties
|
||||
# tools given in the context override the tools in the session properties
|
||||
if self._context and self._context.tools:
|
||||
settings.tools = self._context.tools
|
||||
|
||||
@@ -43,6 +43,8 @@ class OpenPipeLLMService(OpenAILLMService):
|
||||
for model training and evaluation.
|
||||
"""
|
||||
|
||||
_settings: OpenPipeLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -34,6 +34,8 @@ class OpenRouterLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: OpenRouterLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -38,6 +38,8 @@ class PerplexityLLMService(OpenAILLMService):
|
||||
in token usage reporting between Perplexity (incremental) and OpenAI (final summary).
|
||||
"""
|
||||
|
||||
_settings: PerplexityLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -30,6 +30,8 @@ class QwenLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: QwenLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -42,6 +42,8 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: SambaNovaLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -30,6 +30,8 @@ class TogetherLLMService(OpenAILLMService):
|
||||
maintaining full compatibility with OpenAI's interface and functionality.
|
||||
"""
|
||||
|
||||
_settings: TogetherLLMSettings
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
|
||||
Reference in New Issue
Block a user