Update AIService.set_model_name to AIService._sync_model_name_to_metrics to:

- indicate clearly that it's not meant for public use
- make it clear the `self._settings` is the single source of truth for model information
- set the stage for an upcoming change where `AIService` subclasses won't have to ever worry about explicitly calling an `AIService` method to sync model name to metrics

Across all services, switch from accessing `self._model_name` or `self.model_name` in favor of `self._settings.model`.
This commit is contained in:
Paul Kompfner
2026-02-20 11:42:24 -05:00
parent f5b86d9cdc
commit 29e2a861dc
54 changed files with 173 additions and 177 deletions

View File

@@ -42,27 +42,25 @@ class AIService(FrameProcessor):
**kwargs: Additional arguments passed to the parent FrameProcessor.
"""
super().__init__(**kwargs)
self._model_name: str = ""
self._settings: ServiceSettings = ServiceSettings()
self._settings: ServiceSettings = ServiceSettings(model="")
self._session_properties: Dict[str, Any] = {}
@property
def model_name(self) -> str:
"""Get the current model name.
def _sync_model_name_to_metrics(self):
"""Sync the current AI model name (in `self._settings.model`) for usage in metrics.
Returns:
The name of the AI model being used.
"""
return self._model_name
We don't store model name here because there's already a single source
of truth for it in `self._settings.model`. This method is just for
syncing the model name to the metrics data.
def set_model_name(self, model: str):
"""Set the AI model name and update metrics.
TODO: as a next step we should make it so that service classes pass
model into `super().__init__` and `AIService` can be responsible for
syncing its initial value to metrics, just as it's responsible for
syncing any updates to its value to metrics via `_update_settings`.
Args:
model: The name of the AI model to use.
"""
self._model_name = model
self.set_core_metrics_data(MetricsData(processor=self.name, model=self._model_name))
self.set_core_metrics_data(MetricsData(processor=self.name, model=self._settings.model))
async def start(self, frame: StartFrame):
"""Start the AI service.
@@ -117,7 +115,7 @@ class AIService(FrameProcessor):
changed = self._settings.apply_update(update)
if "model" in changed:
self.set_model_name(self._settings.model)
self._sync_model_name_to_metrics()
if changed:
logger.info(f"{self.name}: updated settings fields: {set(changed)}")

View File

@@ -237,7 +237,6 @@ class AnthropicLLMService(LLMService):
self._client = client or AsyncAnthropic(
api_key=api_key
) # if the client is provided, use it and remove it, otherwise create a new one
self.set_model_name(model)
self._retry_timeout_secs = retry_timeout_secs
self._retry_on_timeout = retry_on_timeout
self._settings = AnthropicLLMSettings(
@@ -258,6 +257,7 @@ class AnthropicLLMService(LLMService):
thinking=params.thinking,
extra=params.extra if isinstance(params.extra, dict) else {},
)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate usage metrics.
@@ -324,7 +324,7 @@ class AnthropicLLMService(LLMService):
# Build params using the same method as streaming completions
params = {
"model": self.model_name,
"model": self._settings.model,
"max_tokens": max_tokens if max_tokens is not None else self._settings.max_tokens,
"stream": False,
"temperature": self._settings.temperature,
@@ -438,7 +438,7 @@ class AnthropicLLMService(LLMService):
await self.start_ttfb_metrics()
params = {
"model": self.model_name,
"model": self._settings.model,
"max_tokens": self._settings.max_tokens,
"stream": True,
"temperature": self._settings.temperature,

View File

@@ -171,8 +171,7 @@ class AsyncAITTSService(AudioContextTTSService):
if params.language
else None,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._receive_task = None
self._keepalive_task = None
@@ -513,7 +512,7 @@ class AsyncAIHttpTTSService(TTSService):
if params.language
else None,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._session = aiohttp_session
@@ -562,7 +561,7 @@ class AsyncAIHttpTTSService(TTSService):
voice_config = {"mode": "id", "id": self._settings.voice}
await self.start_ttfb_metrics()
payload = {
"model_id": self._model_name,
"model_id": self._settings.model,
"transcript": text,
"voice": voice_config,
"output_format": {

View File

@@ -820,7 +820,6 @@ class AWSBedrockLLMService(LLMService):
"config": client_config,
}
self.set_model_name(model)
self._retry_timeout_secs = retry_timeout_secs
self._retry_on_timeout = retry_on_timeout
self._settings = AWSBedrockLLMSettings(
@@ -833,6 +832,7 @@ class AWSBedrockLLMService(LLMService):
if isinstance(params.additional_model_request_fields, dict)
else {},
)
self._sync_model_name_to_metrics()
logger.info(f"Using AWS Bedrock model: {model}")
@@ -895,7 +895,7 @@ class AWSBedrockLLMService(LLMService):
inference_config["maxTokens"] = max_tokens
request_params = {
"modelId": self.model_name,
"modelId": self._settings.model,
"messages": messages,
"additionalModelRequestFields": self._settings.additional_model_request_fields,
}
@@ -1052,7 +1052,7 @@ class AWSBedrockLLMService(LLMService):
# Prepare request parameters
request_params = {
"modelId": self.model_name,
"modelId": self._settings.model,
"messages": messages,
"additionalModelRequestFields": self._settings.additional_model_request_fields,
}

View File

@@ -269,7 +269,7 @@ class AWSNovaSonicLLMService(LLMService):
top_p=params.top_p,
endpointing_sensitivity=params.endpointing_sensitivity,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
# Audio I/O config (hardware settings, not runtime-tunable)
self._input_sample_rate = params.input_sample_rate

View File

@@ -54,7 +54,8 @@ class AzureImageGenServiceREST(ImageGenService):
self._api_key = api_key
self._azure_endpoint = endpoint
self._api_version = api_version
self.set_model_name(model)
self._settings.model = model
self._sync_model_name_to_metrics()
self._image_size = image_size
self._aiohttp_session = aiohttp_session

View File

@@ -236,8 +236,7 @@ class CambTTSService(TTSService):
),
user_instructions=params.user_instructions,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._client = None
@@ -272,7 +271,7 @@ class CambTTSService(TTSService):
# Use model-specific sample rate if not explicitly specified
if not self._init_sample_rate:
self._sample_rate = MODEL_SAMPLE_RATES.get(self.model_name, 22050)
self._sample_rate = MODEL_SAMPLE_RATES.get(self._settings.model, 22050)
@traced_tts
async def run_tts(self, text: str, context_id: str) -> AsyncGenerator[Frame, None]:
@@ -300,12 +299,12 @@ class CambTTSService(TTSService):
"text": text,
"voice_id": self._settings.voice,
"language": self._settings.language,
"speech_model": self.model_name,
"speech_model": self._settings.model,
"output_configuration": StreamTtsOutputConfiguration(format="pcm_s16le"),
}
# Add user instructions if using mars-instruct model
if self._model_name == "mars-instruct" and self._settings.user_instructions:
if self._settings.model == "mars-instruct" and self._settings.user_instructions:
tts_kwargs["user_instructions"] = self._settings.user_instructions
await self.start_tts_usage_metrics(text)

View File

@@ -201,7 +201,7 @@ class CartesiaSTTService(WebsocketSTTService):
language=merged_options.get("language"),
encoding=merged_options.get("encoding", "pcm_s16le"),
)
self.set_model_name(merged_options["model"])
self._sync_model_name_to_metrics()
self._api_key = api_key
self._base_url = base_url or "api.cartesia.ai"
self._receive_task = None

View File

@@ -330,6 +330,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
self._cartesia_version = cartesia_version
self._url = url
self._settings = CartesiaTTSSettings(
model=model,
output_container=container,
output_encoding=encoding,
output_sample_rate=0,
@@ -342,7 +343,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
pronunciation_dict_id=params.pronunciation_dict_id,
voice=voice_id,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._context_id = None
self._receive_task = None
@@ -457,7 +458,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
"transcript": text,
"continue": continue_transcript,
"context_id": self._context_id,
"model_id": self.model_name,
"model_id": self._settings.model,
"voice": voice_config,
"output_format": {
"container": self._settings.output_container,
@@ -465,7 +466,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
"sample_rate": self._settings.output_sample_rate,
},
"add_timestamps": add_timestamps,
"use_original_timestamps": False if self.model_name == "sonic" else True,
"use_original_timestamps": False if self._settings.model == "sonic" else True,
}
if is_given(self._settings.language) and self._settings.language:
@@ -741,7 +742,7 @@ class CartesiaHttpTTSService(TTSService):
generation_config=params.generation_config,
pronunciation_dict_id=params.pronunciation_dict_id,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._client = AsyncCartesia(
api_key=api_key,
@@ -829,7 +830,7 @@ class CartesiaHttpTTSService(TTSService):
}
payload = {
"model_id": self._model_name,
"model_id": self._settings.model,
"transcript": text,
"voice": voice_config,
"output_format": output_format,

View File

@@ -66,7 +66,7 @@ class CerebrasLLMService(OpenAILLMService):
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"seed": self._settings.seed,
"temperature": self._settings.temperature,

View File

@@ -212,7 +212,7 @@ class DeepgramFluxSTTService(WebsocketSTTService):
tag=params.tag or [],
min_confidence=params.min_confidence,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._api_key = api_key
self._url = url
self._should_interrupt = should_interrupt

View File

@@ -143,13 +143,13 @@ class DeepgramSTTService(STTService):
if "language" in merged_options and isinstance(merged_options["language"], Language):
merged_options["language"] = merged_options["language"].value
self.set_model_name(merged_options["model"])
merged_live_options = LiveOptions(**merged_options)
self._settings = DeepgramSTTSettings(
model=merged_options.get("model"),
language=merged_options.get("language"),
live_options=merged_live_options,
)
self._sync_model_name_to_metrics()
self._addons = addons
self._should_interrupt = should_interrupt
@@ -225,7 +225,7 @@ class DeepgramSTTService(STTService):
elif "live_options" in changed and self._settings.live_options.model is not None:
# Only live_options was given → pull model up.
self._settings.model = self._settings.live_options.model
self.set_model_name(self._settings.model)
self._sync_model_name_to_metrics()
# --- Sync language -----------------------------------------------
if language_given:

View File

@@ -143,13 +143,13 @@ class DeepgramSageMakerSTTService(STTService):
if "language" in merged_options and isinstance(merged_options["language"], Language):
merged_options["language"] = merged_options["language"].value
self.set_model_name(merged_options["model"])
merged_live_options = LiveOptions(**merged_options)
self._settings = DeepgramSageMakerSTTSettings(
model=merged_options.get("model"),
language=merged_options.get("language"),
live_options=merged_live_options,
)
self._sync_model_name_to_metrics()
self._client: Optional[SageMakerBidiClient] = None
self._response_task: Optional[asyncio.Task] = None
@@ -193,7 +193,7 @@ class DeepgramSageMakerSTTService(STTService):
elif "live_options" in changed and self._settings.live_options.model is not None:
# Only live_options was given → pull model up.
self._settings.model = self._settings.live_options.model
self.set_model_name(self._settings.model)
self._sync_model_name_to_metrics()
# --- Sync language -----------------------------------------------
if language_given:

View File

@@ -65,7 +65,7 @@ class DeepSeekLLMService(OpenAILLMService):
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"stream_options": {"include_usage": True},
"frequency_penalty": self._settings.frequency_penalty,

View File

@@ -281,7 +281,7 @@ class ElevenLabsSTTService(SegmentedSTTService):
else "eng",
tag_audio_events=params.tag_audio_events,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if the service can generate processing metrics.
@@ -531,7 +531,7 @@ class ElevenLabsRealtimeSTTService(WebsocketSTTService):
enable_logging=params.enable_logging,
include_language_detection=params.include_language_detection,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if the service can generate processing metrics.

View File

@@ -423,7 +423,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
enable_logging=params.enable_logging,
apply_text_normalization=params.apply_text_normalization,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._output_format = "" # initialized in start()
self._voice_settings = self._set_voice_settings()
@@ -607,7 +607,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
logger.debug("Connecting to ElevenLabs")
voice_id = self._settings.voice
model = self.model_name
model = self._settings.model
output_format = self._output_format
url = f"{self._url}/v1/text-to-speech/{voice_id}/multi-stream-input?model_id={model}&output_format={output_format}&auto_mode={self._settings.auto_mode}"
@@ -929,7 +929,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
speed=params.speed,
apply_text_normalization=params.apply_text_normalization,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._output_format = "" # initialized in start()
self._voice_settings = self._set_voice_settings()
self._pronunciation_dictionary_locators = params.pronunciation_dictionary_locators
@@ -1100,7 +1100,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
payload: Dict[str, Union[str, Dict[str, Union[float, bool]]]] = {
"text": text,
"model_id": self._model_name,
"model_id": self._settings.model,
}
# Include previous text as context if available
@@ -1122,7 +1122,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
payload["apply_text_normalization"] = self._settings.apply_text_normalization
language = self._settings.language
if self._model_name in ELEVENLABS_MULTILINGUAL_MODELS and language:
if self._settings.model in ELEVENLABS_MULTILINGUAL_MODELS and language:
payload["language_code"] = language
logger.debug(f"Using language code: {language}")
elif language:

View File

@@ -78,7 +78,8 @@ class FalImageGenService(ImageGenService):
**kwargs: Additional arguments passed to parent ImageGenService.
"""
super().__init__(**kwargs)
self.set_model_name(model)
self._settings.model = model
self._sync_model_name_to_metrics()
self._params = params
self._aiohttp_session = aiohttp_session
if key:
@@ -103,7 +104,7 @@ class FalImageGenService(ImageGenService):
logger.debug(f"Generating image from prompt: {prompt}")
response = await fal_client.run_async(
self.model_name,
self._settings.model,
arguments={"prompt": prompt, **self._params.model_dump(exclude_none=True)},
)

View File

@@ -66,7 +66,7 @@ class FireworksLLMService(OpenAILLMService):
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"frequency_penalty": self._settings.frequency_penalty,
"presence_penalty": self._settings.presence_penalty,

View File

@@ -176,6 +176,7 @@ class FishAudioTTSService(InterruptibleTTSService):
self._request_id = None
self._settings = FishAudioTTSSettings(
model=model_id,
voice=reference_id,
fish_sample_rate=0,
latency=params.latency,
@@ -185,8 +186,7 @@ class FishAudioTTSService(InterruptibleTTSService):
prosody_volume=params.prosody_volume,
reference_id=reference_id,
)
self.set_model_name(model_id)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -267,7 +267,7 @@ class FishAudioTTSService(InterruptibleTTSService):
logger.debug("Connecting to Fish Audio")
headers = {"Authorization": f"Bearer {self._api_key}"}
headers["model"] = self.model_name
headers["model"] = self._settings.model
self._websocket = await websocket_connect(self._base_url, additional_headers=headers)
# Send initial start message with ormsgpack

View File

@@ -279,9 +279,9 @@ class GladiaSTTService(WebsocketSTTService):
self._api_key = api_key
self._region = region
self._url = url
self.set_model_name(model)
self._receive_task = None
self._settings = GladiaSTTSettings(model=model, input_params=params)
self._sync_model_name_to_metrics()
# Session management
self._session_url = None
@@ -328,7 +328,7 @@ class GladiaSTTService(WebsocketSTTService):
"bit_depth": params.bit_depth or 16,
"sample_rate": self.sample_rate,
"channels": params.channels or 1,
"model": self._model_name,
"model": self._settings.model,
}
# Add custom_metadata if provided

View File

@@ -701,7 +701,6 @@ class GeminiLiveLLMService(LLMService):
self._last_sent_time = 0
self._base_url = base_url
self.set_model_name(model)
self._voice_id = voice_id
self._language_code = params.language
@@ -763,6 +762,7 @@ class GeminiLiveLLMService(LLMService):
proactivity=params.proactivity or {},
extra=params.extra if isinstance(params.extra, dict) else {},
)
self._sync_model_name_to_metrics()
self._file_api_base_url = file_api_base_url
self._file_api: Optional[GeminiFileAPI] = None
@@ -1230,7 +1230,9 @@ class GeminiLiveLLMService(LLMService):
await self.push_error(error_msg=f"Initialization error: {e}", exception=e)
async def _connection_task_handler(self, config: LiveConnectConfig):
async with self._client.aio.live.connect(model=self._model_name, config=config) as session:
async with self._client.aio.live.connect(
model=self._settings.model, config=config
) as session:
logger.info("Connected to Gemini service")
# Mark connection start time

View File

@@ -79,7 +79,9 @@ class GoogleImageGenService(ImageGenService):
http_options = update_google_client_http_options(http_options)
self._client = genai.Client(api_key=api_key, http_options=http_options)
self.set_model_name(self._params.model)
self._settings.model = self._params.model
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.

View File

@@ -797,7 +797,6 @@ class GoogleLLMService(LLMService):
params = params or GoogleLLMService.InputParams()
self.set_model_name(model)
self._api_key = api_key
self._system_instruction = system_instruction
self._http_options = update_google_client_http_options(http_options)
@@ -811,6 +810,7 @@ class GoogleLLMService(LLMService):
thinking=params.thinking,
extra=params.extra if isinstance(params.extra, dict) else {},
)
self._sync_model_name_to_metrics()
self._tools = tools
self._tool_config = tool_config
@@ -870,7 +870,7 @@ class GoogleLLMService(LLMService):
# Use the new google-genai client's async method
response = await self._client.aio.models.generate_content(
model=self._model_name,
model=self._settings.model,
contents=messages,
config=generation_config,
)
@@ -930,10 +930,10 @@ class GoogleLLMService(LLMService):
# There's no way to introspect on model capabilities, so
# to check for models that we know default to thinkin on
# and can be configured to turn it off.
if not self._model_name.startswith("gemini-2.5-flash"):
if not self._settings.model.startswith("gemini-2.5-flash"):
return
# If we have an image model, we don't use a budget either.
if "image" in self._model_name:
if "image" in self._settings.model:
return
# If thinking_config is already set, don't override it.
if "thinking_config" in generation_params:
@@ -974,7 +974,7 @@ class GoogleLLMService(LLMService):
await self.start_ttfb_metrics()
return await self._client.aio.models.generate_content_stream(
model=self._model_name,
model=self._settings.model,
contents=messages,
config=generation_config,
)

View File

@@ -62,7 +62,7 @@ class GroqSTTService(BaseWhisperSTTService):
# Build kwargs dict with only set parameters
kwargs = {
"file": ("audio.wav", audio, "audio/wav"),
"model": self.model_name,
"model": self._settings.model,
# Use verbose_json to get probability metrics
"response_format": "verbose_json" if self._include_prob_metrics else "json",
"language": self._language,

View File

@@ -108,7 +108,6 @@ class GroqTTSService(TTSService):
params = params or GroqTTSService.InputParams()
self._api_key = api_key
self._model_name = model_name
self._output_format = output_format
self._params = params
@@ -120,6 +119,7 @@ class GroqTTSService(TTSService):
speed=params.speed,
groq_sample_rate=sample_rate,
)
self._sync_model_name_to_metrics()
self._client = AsyncGroq(api_key=self._api_key)
@@ -149,7 +149,7 @@ class GroqTTSService(TTSService):
try:
response = await self._client.audio.speech.create(
model=self._model_name,
model=self._settings.model,
voice=self._settings.voice,
response_format=self._output_format,
input=text,

View File

@@ -105,8 +105,7 @@ class HathoraSTTService(SegmentedSTTService):
language=params.language,
config=params.config,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.

View File

@@ -123,8 +123,7 @@ class HathoraTTSService(TTSService):
speed=params.speed,
config=params.config,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.

View File

@@ -173,7 +173,7 @@ class InworldHttpTTSService(WordTTSService):
self._cumulative_time = 0.0
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -562,7 +562,7 @@ class InworldTTSService(AudioContextWordTTSService):
# Track the end time of the last word in the current generation
self._generation_end_time = 0.0
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.

View File

@@ -122,13 +122,13 @@ class LmntTTSService(InterruptibleTTSService):
)
self._api_key = api_key
self.set_model_name(model)
self._settings = LmntTTSSettings(
model=model,
voice=voice_id,
language=self.language_to_service_language(language),
format="raw",
)
self._sync_model_name_to_metrics()
self._receive_task = None
self._context_id: Optional[str] = None
@@ -238,7 +238,7 @@ class LmntTTSService(InterruptibleTTSService):
"format": self._settings.format,
"sample_rate": self.sample_rate,
"language": self._settings.language,
"model": self.model_name,
"model": self._settings.model,
}
# Connect to LMNT's websocket directly

View File

@@ -235,7 +235,6 @@ class MiniMaxHttpTTSService(TTSService):
self._group_id = group_id
self._base_url = f"{base_url}?GroupId={group_id}"
self._session = aiohttp_session
self._model_name = model
# Create voice settings
self._settings = MiniMaxTTSSettings(
@@ -249,9 +248,7 @@ class MiniMaxHttpTTSService(TTSService):
audio_format="pcm",
audio_channel=1,
)
# Set model
self.set_model_name(model)
self._sync_model_name_to_metrics()
# Add language boost if provided
if params.language:
@@ -318,14 +315,6 @@ class MiniMaxHttpTTSService(TTSService):
"""
return language_to_minimax_language(language)
def set_model_name(self, model: str):
"""Set the TTS model to use.
Args:
model: The model name to use for synthesis.
"""
self._model_name = model
async def start(self, frame: StartFrame):
"""Start the MiniMax TTS service.
@@ -382,7 +371,7 @@ class MiniMaxHttpTTSService(TTSService):
"stream": self._settings.stream,
"voice_setting": voice_setting,
"audio_setting": audio_setting,
"model": self._model_name,
"model": self._settings.model,
"text": text,
}
if is_given(self._settings.language_boost):

View File

@@ -180,7 +180,7 @@ class MistralLLMService(OpenAILLMService):
fixed_messages = self._apply_mistral_fixups(params_from_context["messages"])
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"messages": fixed_messages,
"tools": params_from_context["tools"],

View File

@@ -81,7 +81,8 @@ class MoondreamService(VisionService):
"""
super().__init__(**kwargs)
self.set_model_name(model)
self._settings.model = model
self._sync_model_name_to_metrics()
if not use_cpu:
device, dtype = detect_device()

View File

@@ -181,10 +181,10 @@ class NvidiaSTTService(STTService):
self._function_id = model_function_map.get("function_id")
self._settings = NvidiaSTTSettings(
model=model_function_map.get("model_name"),
language=params.language,
)
self.set_model_name(model_function_map.get("model_name"))
self._sync_model_name_to_metrics()
self._asr_service = None
self._queue = None
@@ -282,7 +282,7 @@ class NvidiaSTTService(STTService):
if not self._thread_task:
self._thread_task = self.create_task(self._thread_task_handler())
logger.debug(f"Initialized NvidiaSTTService with model: {self.model_name}")
logger.debug(f"Initialized NvidiaSTTService with model: {self._settings.model}")
async def stop(self, frame: EndFrame):
"""Stop the NVIDIA Riva STT service and clean up resources.
@@ -467,9 +467,6 @@ class NvidiaSegmentedSTTService(SegmentedSTTService):
params = params or NvidiaSegmentedSTTService.InputParams()
# Set model name
self.set_model_name(model_function_map.get("model_name"))
# Initialize NVIDIA Riva settings
self._api_key = api_key
self._server = server
@@ -488,6 +485,7 @@ class NvidiaSegmentedSTTService(SegmentedSTTService):
self._config = None
self._asr_service = None
self._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,
@@ -496,6 +494,7 @@ class NvidiaSegmentedSTTService(SegmentedSTTService):
boosted_lm_words=params.boosted_lm_words,
boosted_lm_score=params.boosted_lm_score,
)
self._sync_model_name_to_metrics()
def language_to_service_language(self, language: Language) -> Optional[str]:
"""Convert pipecat Language enum to NVIDIA Riva's language code.
@@ -578,7 +577,7 @@ class NvidiaSegmentedSTTService(SegmentedSTTService):
await super().start(frame)
self._initialize_client()
self._config = self._create_recognition_config()
logger.debug(f"Initialized NvidiaSegmentedSTTService with model: {self.model_name}")
logger.debug(f"Initialized NvidiaSegmentedSTTService with model: {self._settings.model}")
async def _update_settings(self, update: STTSettings) -> dict[str, Any]:
"""Apply a settings update and sync internal state.

View File

@@ -112,11 +112,12 @@ class NvidiaTTSService(TTSService):
self._function_id = model_function_map.get("function_id")
self._use_ssl = use_ssl
self._settings = NvidiaTTSSettings(
model=model_function_map.get("model_name"),
voice=voice_id,
language=params.language,
quality=params.quality,
)
self.set_model_name(model_function_map.get("model_name"))
self._sync_model_name_to_metrics()
self._service = None
self._config = None
@@ -192,7 +193,7 @@ class NvidiaTTSService(TTSService):
await super().start(frame)
self._initialize_client()
self._config = self._create_synthesis_config()
logger.debug(f"Initialized NvidiaTTSService with model: {self.model_name}")
logger.debug(f"Initialized NvidiaTTSService with model: {self._settings.model}")
@traced_tts
async def run_tts(self, text: str, context_id: str) -> AsyncGenerator[Frame, None]:

View File

@@ -151,7 +151,7 @@ class BaseOpenAILLMService(LLMService):
)
self._retry_timeout_secs = retry_timeout_secs
self._retry_on_timeout = retry_on_timeout
self.set_model_name(model)
self._sync_model_name_to_metrics()
self._full_model_name: str = ""
self._client = self.create_client(
api_key=api_key,
@@ -265,7 +265,7 @@ class BaseOpenAILLMService(LLMService):
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"stream_options": {"include_usage": True},
"frequency_penalty": self._settings.frequency_penalty,

View File

@@ -53,7 +53,8 @@ class OpenAIImageGenService(ImageGenService):
model: DALL-E model to use for generation. Defaults to "dall-e-3".
"""
super().__init__()
self.set_model_name(model)
self._settings.model = model
self._sync_model_name_to_metrics()
self._image_size = image_size
self._client = AsyncOpenAI(api_key=api_key, base_url=base_url)
self._aiohttp_session = aiohttp_session
@@ -70,7 +71,7 @@ class OpenAIImageGenService(ImageGenService):
logger.debug(f"Generating image from prompt: {prompt}")
image = await self._client.images.generate(
prompt=prompt, model=self.model_name, n=1, size=self._image_size
prompt=prompt, model=self._settings.model, n=1, size=self._image_size
)
image_url = image.data[0].url

View File

@@ -175,12 +175,12 @@ class OpenAIRealtimeLLMService(LLMService):
self.api_key = api_key
self.base_url = full_url
self.set_model_name(model)
self._settings = OpenAIRealtimeLLMSettings(
model=model,
session_properties=session_properties or events.SessionProperties(),
)
self._sync_model_name_to_metrics()
self._audio_input_paused = start_audio_paused
self._video_input_paused = start_video_paused
self._video_frame_detail = video_frame_detail

View File

@@ -100,24 +100,24 @@ class OpenAISTTService(BaseWhisperSTTService):
# Build kwargs dict with only set parameters
kwargs = {
"file": ("audio.wav", audio, "audio/wav"),
"model": self.model_name,
"language": self._language,
"model": self._settings.model,
"language": self._settings.language,
}
if self._include_prob_metrics:
# GPT-4o-transcribe models only support logprobs (not verbose_json)
if self.model_name in ("gpt-4o-transcribe", "gpt-4o-mini-transcribe"):
if self._settings.model in ("gpt-4o-transcribe", "gpt-4o-mini-transcribe"):
kwargs["response_format"] = "json"
kwargs["include"] = ["logprobs"]
else:
# Whisper models support verbose_json
kwargs["response_format"] = "verbose_json"
if self._prompt is not None:
kwargs["prompt"] = self._prompt
if self._settings.prompt is not None:
kwargs["prompt"] = self._settings.prompt
if self._temperature is not None:
kwargs["temperature"] = self._temperature
if self._settings.temperature is not None:
kwargs["temperature"] = self._settings.temperature
return await self._client.audio.transcriptions.create(**kwargs)
@@ -226,7 +226,6 @@ class OpenAIRealtimeSTTService(WebsocketSTTService):
self._api_key = api_key
self._base_url = base_url
self.set_model_name(model)
self._prompt = prompt
self._turn_detection = turn_detection
@@ -238,6 +237,7 @@ class OpenAIRealtimeSTTService(WebsocketSTTService):
language=language,
prompt=prompt,
)
self._sync_model_name_to_metrics()
self._receive_task = None
self._session_ready = False
@@ -437,7 +437,7 @@ class OpenAIRealtimeSTTService(WebsocketSTTService):
async def _send_session_update(self):
"""Send ``session.update`` to configure the transcription session."""
transcription: dict = {"model": self.model_name}
transcription: dict = {"model": self._settings.model}
language_code = (
self._language_to_code(self._settings.language) if self._settings.language else None

View File

@@ -134,7 +134,6 @@ class OpenAITTSService(TTSService):
)
super().__init__(sample_rate=sample_rate, **kwargs)
self.set_model_name(model)
self._client = AsyncOpenAI(api_key=api_key, base_url=base_url)
if instructions or speed:
@@ -154,6 +153,7 @@ class OpenAITTSService(TTSService):
instructions=params.instructions if params else instructions,
speed=params.speed if params else speed,
)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -194,7 +194,7 @@ class OpenAITTSService(TTSService):
# Setup API parameters
create_params = {
"input": text,
"model": self.model_name,
"model": self._settings.model,
"voice": VALID_VOICES[self._settings.voice],
"response_format": "pcm",
}

View File

@@ -160,12 +160,12 @@ class OpenAIRealtimeBetaLLMService(LLMService):
self.api_key = api_key
self.base_url = full_url
self.set_model_name(model)
self._settings = OpenAIRealtimeBetaLLMSettings(
model=model,
session_properties=session_properties or events.SessionProperties(),
)
self._sync_model_name_to_metrics()
self._audio_input_paused = start_audio_paused
self._send_transcription_frames = send_transcription_frames
self._websocket = None

View File

@@ -72,8 +72,7 @@ class OpenRouterLLMService(OpenAILLMService):
Transformed parameters ready for the API call.
"""
params = super().build_chat_completion_params(params_from_context)
model = getattr(self, "model_name", getattr(self, "model", "")).lower()
if "gemini" in model:
if "gemini" in self._settings.model.lower():
messages = params.get("messages", [])
if not messages:
return params

View File

@@ -66,7 +66,7 @@ class PerplexityLLMService(OpenAILLMService):
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"messages": params_from_context["messages"],
}

View File

@@ -204,7 +204,7 @@ class PlayHTTTSService(InterruptibleTTSService):
speed=params.speed,
seed=params.seed,
)
self.set_model_name(voice_engine)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -545,6 +545,7 @@ class PlayHTHttpTTSService(TTSService):
voice_engine = voice_engine.replace("-ws", "")
self._settings = PlayHTTTSSettings(
model=voice_engine,
voice=voice_url,
language=self.language_to_service_language(params.language)
if params.language
@@ -554,7 +555,7 @@ class PlayHTHttpTTSService(TTSService):
speed=params.speed,
seed=params.seed,
)
self.set_model_name(voice_engine)
self._sync_model_name_to_metrics()
async def start(self, frame: StartFrame):
"""Start the PlayHT HTTP TTS service.

View File

@@ -75,7 +75,6 @@ class RimeTTSSettings(TTSSettings):
"""Settings for Rime WS JSON and HTTP TTS services.
Parameters:
modelId: Rime model identifier.
audioFormat: Audio output format.
samplingRate: Audio sample rate.
lang: Rime language code.
@@ -86,7 +85,6 @@ class RimeTTSSettings(TTSSettings):
inlineSpeedAlpha: Inline speed control markup.
"""
modelId: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
audioFormat: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
samplingRate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
lang: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
@@ -104,7 +102,6 @@ class RimeNonJsonTTSSettings(TTSSettings):
"""Settings for Rime non-JSON WS TTS service.
Parameters:
modelId: Rime model identifier.
audioFormat: Audio output format.
samplingRate: Audio sample rate.
lang: Rime language code.
@@ -114,7 +111,6 @@ class RimeNonJsonTTSSettings(TTSSettings):
top_p: Cumulative probability threshold (0.0-1.0).
"""
modelId: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
audioFormat: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
samplingRate: int | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
lang: str | _NotGiven = field(default_factory=lambda: NOT_GIVEN)
@@ -210,7 +206,7 @@ class RimeTTSService(AudioContextWordTTSService):
self._model = model
self._settings = RimeTTSSettings(
voice=voice_id,
modelId=model,
model=model,
audioFormat="pcm",
samplingRate=0,
lang=self.language_to_service_language(params.language) if params.language else "eng",
@@ -219,6 +215,7 @@ class RimeTTSService(AudioContextWordTTSService):
pauseBetweenBrackets=json.dumps(params.pause_between_brackets),
phonemizeBetweenBrackets=json.dumps(params.phonemize_between_brackets),
)
self._sync_model_name_to_metrics()
# State tracking
self._context_id = None # Tracks current turn
@@ -353,7 +350,7 @@ class RimeTTSService(AudioContextWordTTSService):
f"{k}={v}"
for k, v in {
"speaker": self._settings.voice,
"modelId": self._settings.modelId,
"modelId": self._settings.model,
"audioFormat": self._settings.audioFormat,
"samplingRate": self._settings.samplingRate,
"lang": self._settings.lang,
@@ -589,6 +586,7 @@ class RimeHttpTTSService(TTSService):
self._session = aiohttp_session
self._base_url = "https://users.rime.ai/v1/rime-tts"
self._settings = RimeTTSSettings(
model=model,
lang=self.language_to_service_language(params.language) if params.language else "eng",
speedAlpha=params.speed_alpha,
reduceLatency=params.reduce_latency,
@@ -597,7 +595,7 @@ class RimeHttpTTSService(TTSService):
inlineSpeedAlpha=params.inline_speed_alpha if params.inline_speed_alpha else NOT_GIVEN,
voice=voice_id,
)
self.set_model_name(model)
self._sync_model_name_to_metrics()
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -648,7 +646,7 @@ class RimeHttpTTSService(TTSService):
payload["inlineSpeedAlpha"] = self._settings.inlineSpeedAlpha
payload["text"] = text
payload["speaker"] = self._settings.voice
payload["modelId"] = self._model_name
payload["modelId"] = self._settings.model
payload["samplingRate"] = self.sample_rate
# Arcana does not support PCM audio
@@ -769,7 +767,7 @@ class RimeNonJsonTTSService(InterruptibleTTSService):
self._model = model
self._settings = RimeNonJsonTTSSettings(
voice=voice_id,
modelId=model,
model=model,
audioFormat=audio_format,
samplingRate=sample_rate,
lang=self.language_to_service_language(params.language)
@@ -782,6 +780,7 @@ class RimeNonJsonTTSService(InterruptibleTTSService):
temperature=params.temperature if params.temperature is not None else NOT_GIVEN,
top_p=params.top_p if params.top_p is not None else NOT_GIVEN,
)
self._sync_model_name_to_metrics()
# Add any extra parameters for future compatibility
if params.extra:
self._settings.extra.update(params.extra)
@@ -863,7 +862,7 @@ class RimeNonJsonTTSService(InterruptibleTTSService):
# Build URL with query parameters (only given, non-None values)
settings_dict = {
"speaker": self._settings.voice,
"modelId": self._settings.modelId,
"modelId": self._settings.model,
"audioFormat": self._settings.audioFormat,
"samplingRate": self._settings.samplingRate,
}
@@ -981,10 +980,6 @@ class RimeNonJsonTTSService(InterruptibleTTSService):
"""
changed = await super()._update_settings(update)
# Sync model to settings dict field
if "model" in changed:
self._settings.modelId = self._model_name
if changed:
logger.debug("Settings changed, reconnecting WebSocket with new parameters")
await self._disconnect()

View File

@@ -84,7 +84,7 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
Dictionary of parameters for the chat completion request.
"""
params = {
"model": self.model_name,
"model": self._settings.model,
"stream": True,
"stream_options": {"include_usage": True},
"temperature": self._settings.temperature,

View File

@@ -72,7 +72,7 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore
# Build kwargs dict with only set parameters
kwargs = {
"file": ("audio.wav", audio, "audio/wav"),
"model": self.model_name,
"model": self._settings.model,
"response_format": "json",
"language": self._language,
}

View File

@@ -225,7 +225,6 @@ class SarvamSTTService(STTService):
super().__init__(sample_rate=sample_rate, ttfs_p99_latency=ttfs_p99_latency, **kwargs)
self.set_model_name(model)
self._api_key = api_key
# Store connection parameters
@@ -257,6 +256,7 @@ class SarvamSTTService(STTService):
vad_signals=params.vad_signals,
high_vad_sensitivity=params.high_vad_sensitivity,
)
self._sync_model_name_to_metrics()
if params.vad_signals:
self._register_event_handler("on_speech_started")
@@ -322,7 +322,7 @@ class SarvamSTTService(STTService):
if is_given(update.language) and update.language is not None:
if not self._config.supports_language:
raise ValueError(
f"Model '{self.model_name}' does not support language parameter "
f"Model '{self._settings.model}' does not support language parameter "
"(auto-detects language)."
)
@@ -330,11 +330,13 @@ class SarvamSTTService(STTService):
if is_given(update.prompt) and update.prompt is not None:
if not self._config.supports_prompt:
raise ValueError(
f"Model '{self.model_name}' does not support prompt parameter."
f"Model '{self._settings.model}' does not support prompt parameter."
)
if is_given(update.mode) and update.mode is not None:
if not self._config.supports_mode:
raise ValueError(f"Model '{self.model_name}' does not support mode parameter.")
raise ValueError(
f"Model '{self._settings.model}' does not support mode parameter."
)
changed = await super()._update_settings(update)
@@ -374,11 +376,13 @@ class SarvamSTTService(STTService):
if not self._config.supports_prompt:
if prompt is not None:
raise ValueError(f"Model '{self.model_name}' does not support prompt parameter.")
raise ValueError(
f"Model '{self._settings.model}' does not support prompt parameter."
)
# If prompt is None and model doesn't support prompts, silently return (no-op)
return
logger.info(f"Updating {self.model_name} prompt.")
logger.info(f"Updating {self._settings.model} prompt.")
self._settings.prompt = prompt
await self._disconnect()
await self._connect()
@@ -460,7 +464,7 @@ class SarvamSTTService(STTService):
try:
# Build common connection parameters
connect_kwargs = {
"model": self.model_name,
"model": self._settings.model,
"sample_rate": str(self.sample_rate),
}

View File

@@ -489,6 +489,7 @@ class SarvamHttpTTSService(TTSService):
model=model,
voice=voice_id,
)
self._sync_model_name_to_metrics()
# Add parameters based on model support
if self._config.supports_pitch:
@@ -506,8 +507,6 @@ class SarvamHttpTTSService(TTSService):
elif params.temperature != 0.6:
logger.warning(f"temperature parameter is ignored for {model}")
self.set_model_name(model)
def can_generate_metrics(self) -> bool:
"""Check if this service can generate processing metrics.
@@ -559,7 +558,7 @@ class SarvamHttpTTSService(TTSService):
"speaker": self._settings.voice,
"sample_rate": self.sample_rate,
"enable_preprocessing": self._settings.enable_preprocessing,
"model": self._model_name,
"model": self._settings.model,
"pace": self._settings.pace if is_given(self._settings.pace) else 1.0,
}
@@ -828,7 +827,6 @@ class SarvamTTSService(InterruptibleTTSService):
# WebSocket endpoint URL with model query parameter
self._websocket_url = f"{url}?model={model}"
self._api_key = api_key
self.set_model_name(model)
# Validate and clamp pace to model's valid range
pace = params.pace
@@ -854,6 +852,7 @@ class SarvamTTSService(InterruptibleTTSService):
model=model,
voice=voice_id,
)
self._sync_model_name_to_metrics()
# Add parameters based on model support
if self._config.supports_pitch:

View File

@@ -195,13 +195,13 @@ class SonioxSTTService(WebsocketSTTService):
self._api_key = api_key
self._url = url
self.set_model_name(params.model)
self._vad_force_turn_endpoint = vad_force_turn_endpoint
self._settings = SonioxSTTSettings(
model=params.model,
input_params=params,
)
self._sync_model_name_to_metrics()
self._final_transcription_buffer = []
self._last_tokens_received: Optional[float] = None
@@ -247,7 +247,7 @@ class SonioxSTTService(WebsocketSTTService):
elif "input_params" in changed and self._settings.input_params.model is not None:
# Only input_params was given → pull model up.
self._settings.model = self._settings.input_params.model
self.set_model_name(self._settings.model)
self._sync_model_name_to_metrics()
# TODO: someday we could reconnect here to apply updated settings.
# Code might look something like the below:
@@ -380,7 +380,7 @@ class SonioxSTTService(WebsocketSTTService):
# Send the initial configuration message.
config = {
"api_key": self._api_key,
"model": self._model_name,
"model": self._settings.model,
"audio_format": params.audio_format,
"num_channels": params.num_channels or 1,
"enable_endpoint_detection": enable_endpoint_detection,

View File

@@ -459,7 +459,7 @@ class SpeechmaticsSTTService(STTService):
# Model + metrics (operating_point comes from the SDK config/preset)
self._settings.model = self._config.operating_point.value
self.set_model_name(self._config.operating_point.value)
self._sync_model_name_to_metrics()
# Message queue
self._stt_msg_queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue()

View File

@@ -492,7 +492,7 @@ class STTService(AIService):
if self.metrics_enabled:
ttfb_data = TTFBMetricsData(
processor=self.name,
model=self.model_name,
model=self._settings.model,
value=ttfb,
)
await super().push_frame(MetricsFrame(data=[ttfb_data]))

View File

@@ -156,7 +156,6 @@ class BaseWhisperSTTService(SegmentedSTTService):
**kwargs: Additional arguments passed to SegmentedSTTService.
"""
super().__init__(ttfs_p99_latency=ttfs_p99_latency, **kwargs)
self.set_model_name(model)
self._client = self._create_client(api_key, base_url)
self._language = self.language_to_service_language(language or Language.EN)
self._prompt = prompt
@@ -170,6 +169,7 @@ class BaseWhisperSTTService(SegmentedSTTService):
prompt=self._prompt,
temperature=self._temperature,
)
self._sync_model_name_to_metrics()
def _create_client(self, api_key: Optional[str], base_url: Optional[str]):
return AsyncOpenAI(api_key=api_key, base_url=base_url)

View File

@@ -236,7 +236,6 @@ class WhisperSTTService(SegmentedSTTService):
super().__init__(**kwargs)
self._device: str = device
self._compute_type = compute_type
self.set_model_name(model if isinstance(model, str) else model.value)
self._no_speech_prob = no_speech_prob
self._model: Optional[WhisperModel] = None
@@ -247,6 +246,7 @@ class WhisperSTTService(SegmentedSTTService):
compute_type=self._compute_type,
no_speech_prob=self._no_speech_prob,
)
self._sync_model_name_to_metrics()
self._load()
@@ -281,7 +281,7 @@ class WhisperSTTService(SegmentedSTTService):
logger.debug("Loading Whisper model...")
self._model = WhisperModel(
self.model_name, device=self._device, compute_type=self._compute_type
self._settings.model, device=self._device, compute_type=self._compute_type
)
logger.debug("Loaded Whisper model")
except ModuleNotFoundError as e:
@@ -370,7 +370,6 @@ class WhisperSTTServiceMLX(WhisperSTTService):
# Skip WhisperSTTService.__init__ and call its parent directly
SegmentedSTTService.__init__(self, **kwargs)
self.set_model_name(model if isinstance(model, str) else model.value)
self._no_speech_prob = no_speech_prob
self._temperature = temperature
@@ -381,6 +380,7 @@ class WhisperSTTServiceMLX(WhisperSTTService):
temperature=self._temperature,
engine="mlx",
)
self._sync_model_name_to_metrics()
# No need to call _load() as MLX Whisper loads models on demand
@@ -421,7 +421,7 @@ class WhisperSTTServiceMLX(WhisperSTTService):
chunk = await asyncio.to_thread(
mlx_whisper.transcribe,
audio_float,
path_or_hf_repo=self.model_name,
path_or_hf_repo=self._settings.model,
temperature=self._temperature,
language=self._settings.language,
)

View File

@@ -44,6 +44,23 @@ T = TypeVar("T")
R = TypeVar("R")
def _get_model_name(service) -> str:
"""Get the model name from a service instance.
This is a bit of a mess — there were multiple places a model name could live.
Soon, self._settings should be the only source of truth about model name.
In fact...it might already be the case, but juuuuust to be safe, we'll
check all the places we used to store it.
"""
return (
getattr(getattr(service, "_settings", None), "model", None)
or getattr(service, "_full_model_name", None)
or getattr(service, "model_name", None)
or getattr(service, "_model_name", None)
or "unknown"
)
def _noop_decorator(func):
"""No-op fallback decorator when tracing is unavailable.
@@ -194,7 +211,7 @@ def traced_tts(func: Optional[Callable] = None, *, name: Optional[str] = None) -
add_tts_span_attributes(
span=span,
service_name=service_class_name,
model=getattr(self, "model_name") or "unknown",
model=_get_model_name(self),
voice_id=getattr(settings, "voice", "unknown"),
text=text,
settings=settings,
@@ -311,7 +328,7 @@ def traced_stt(func: Optional[Callable] = None, *, name: Optional[str] = None) -
add_stt_span_attributes(
span=current_span,
service_name=service_class_name,
model=getattr(self, "model_name") or settings.get("model", "unknown"),
model=_get_model_name(self),
transcript=transcript,
is_final=is_final,
language=str(language) if language else None,
@@ -491,10 +508,7 @@ def traced_llm(func: Optional[Callable] = None, *, name: Optional[str] = None) -
# Add all available attributes to the span
attribute_kwargs = {
"service_name": service_class_name,
"model": getattr(self, "_full_model_name", None)
or getattr(self, "model_name", None)
or params.get("model")
or "unknown",
"model": _get_model_name(self),
"stream": True, # Most LLM services use streaming
"parameters": params,
}
@@ -593,11 +607,7 @@ def traced_gemini_live(operation: str) -> Callable:
) as current_span:
try:
# Base service attributes
model_name = (
getattr(self, "model_name", None)
or getattr(self, "_model_name", None)
or "unknown"
)
model_name = _get_model_name(self)
voice_id = getattr(self, "_voice_id", None)
language_code = getattr(self, "_language_code", None)
settings = getattr(self, "_settings", {})
@@ -900,11 +910,7 @@ def traced_openai_realtime(operation: str) -> Callable:
) as current_span:
try:
# Base service attributes
model_name = (
getattr(self, "model_name", None)
or getattr(self, "_model_name", None)
or "unknown"
)
model_name = _get_model_name(self)
# Operation-specific attribute collection
operation_attrs = {}