Broad service settings refactor, with the primary aim of making service settings discoverable and strongly-typed. Service settings can be updated at runtime with *UpdateSettingsFrames.
Does not (yet) touch `InputParams`, to avoid scope creep and touching something currently part of the public API. But there is a lot of overlap between `*Settings` object fields and `InputParams` fields. Other than discoverability/typing, these are some other improvements brought by this refactor: - There is now a single code path (see `_update_settings_from_typed`) where services can respond to settings changes (by, say, reconnecting if needed), improving maintainability and guaranteeing one and only one reconnection no matter which settings changed - `set_language`/`set_model`/`set_voice`—which we're assuming are usable as public methods, though *not* recommended over `*UpdateSettingsFrame`—all use the same code path as settings updates. They're also now all consistent in that, if a service needs to respond to a change (by, say, reconnecting if needed), any of these methods will kick off that process. Note that this is technically a behavior change. - Several services now properly react to changed settings by reconnecting: - `AWSTranscribeSTTService` - `AzureSTTService` - `SonioxSTTService` - `GladiaSTTService` - `SpeechmaticsSTTService` - `AssemblyAISTTService` - `CartesiaSTTService` - `FishAudioTTSService` (would previously only reconnect when `model` changed) - `GoogleSTTService` - `SpeechmaticsSTTService` (which previously only handled *some* settings updates through a nonstandard public `update_params` method) - `GradiumSTTService` - `NvidiaSegmentedSTTService` (which previously only handled changes to language) - Bookkeeping across various services has been reduced, mostly by deduping ivars; the `self._settings` ivar is treated as the source of truth NOTE: I pretty much guarantee that there are services missed in this PR in terms of bringing to consistency with how updates are handled (like whether changes in certain fields trigger reconnects when they need to). We can squash remaining inconsistencies as we stumble onto them, service by service. The goal here is to get things *mostly* in order, and establish the infrastructure and patterns we'll need going forward.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
"""LMNT text-to-speech service implementation."""
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from typing import AsyncGenerator, Optional
|
||||
|
||||
from loguru import logger
|
||||
@@ -23,6 +24,7 @@ from pipecat.frames.frames import (
|
||||
TTSStoppedFrame,
|
||||
)
|
||||
from pipecat.processors.frame_processor import FrameDirection
|
||||
from pipecat.services.settings import NOT_GIVEN, TTSSettings
|
||||
from pipecat.services.tts_service import InterruptibleTTSService
|
||||
from pipecat.transcriptions.language import Language, resolve_language
|
||||
from pipecat.utils.tracing.service_decorators import traced_tts
|
||||
@@ -71,6 +73,17 @@ def language_to_lmnt_language(language: Language) -> Optional[str]:
|
||||
return resolve_language(language, LANGUAGE_MAP, use_base_code=True)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LmntTTSSettings(TTSSettings):
|
||||
"""Typed settings for LMNT TTS service.
|
||||
|
||||
Parameters:
|
||||
format: Audio output format. Defaults to "raw".
|
||||
"""
|
||||
|
||||
format: str = field(default_factory=lambda: NOT_GIVEN)
|
||||
|
||||
|
||||
class LmntTTSService(InterruptibleTTSService):
|
||||
"""LMNT real-time text-to-speech service.
|
||||
|
||||
@@ -107,12 +120,14 @@ class LmntTTSService(InterruptibleTTSService):
|
||||
)
|
||||
|
||||
self._api_key = api_key
|
||||
self.set_voice(voice_id)
|
||||
self._voice_id = voice_id
|
||||
self.set_model_name(model)
|
||||
self._settings = {
|
||||
"language": self.language_to_service_language(language),
|
||||
"format": "raw", # Use raw format for direct PCM data
|
||||
}
|
||||
self._settings: LmntTTSSettings = LmntTTSSettings(
|
||||
model=model,
|
||||
voice=voice_id,
|
||||
language=self.language_to_service_language(language),
|
||||
format="raw",
|
||||
)
|
||||
self._receive_task = None
|
||||
self._context_id: Optional[str] = None
|
||||
|
||||
@@ -202,9 +217,9 @@ class LmntTTSService(InterruptibleTTSService):
|
||||
init_msg = {
|
||||
"X-API-Key": self._api_key,
|
||||
"voice": self._voice_id,
|
||||
"format": self._settings["format"],
|
||||
"format": self._settings.format,
|
||||
"sample_rate": self.sample_rate,
|
||||
"language": self._settings["language"],
|
||||
"language": self._settings.language,
|
||||
"model": self.model_name,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user