feat(voice): add admin-configurable elevenlabs tts

This commit is contained in:
Yera All
2026-04-11 16:46:43 +05:00
parent 9d0b76deca
commit fc976804e4
14 changed files with 1342 additions and 32 deletions
+54 -1
View File
@@ -2,7 +2,7 @@
from typing import Literal
from pydantic import BaseModel, Field, field_validator, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from services.shared.core import Role
@@ -98,6 +98,59 @@ class VoiceNameCollectionConfigOut(BaseModel):
source: Literal["defaults", "database"] = "defaults"
VoiceTTSProviderName = Literal["yandex", "elevenlabs", "openai"]
VoiceTTSLanguage = Literal["ru", "kz"]
class VoiceTTSLanguageConfig(BaseModel):
model_config = ConfigDict(protected_namespaces=())
voice: str | None = None
model_id: str | None = None
language_code: str | None = None
@field_validator("voice", "model_id", "language_code", mode="before")
@classmethod
def _trim_optional_text(cls, value: str | None) -> str | None:
if value is None:
return None
normalized = str(value).strip()
return normalized or None
class VoiceTTSProviderConfig(BaseModel):
ru: VoiceTTSLanguageConfig = Field(default_factory=VoiceTTSLanguageConfig)
kz: VoiceTTSLanguageConfig = Field(default_factory=VoiceTTSLanguageConfig)
class VoiceTTSVoiceOption(BaseModel):
value: str = Field(min_length=1)
label: str = Field(min_length=1)
@field_validator("value", "label", mode="before")
@classmethod
def _trim_required_option_text(cls, value: str) -> str:
normalized = str(value or "").strip()
if not normalized:
raise ValueError("Option value is required")
return normalized
class VoiceTTSConfig(BaseModel):
provider: VoiceTTSProviderName = "yandex"
yandex: VoiceTTSProviderConfig = Field(default_factory=VoiceTTSProviderConfig)
elevenlabs: VoiceTTSProviderConfig = Field(default_factory=VoiceTTSProviderConfig)
openai: VoiceTTSProviderConfig = Field(default_factory=VoiceTTSProviderConfig)
class VoiceTTSConfigOut(BaseModel):
config: VoiceTTSConfig
updated_at: str | None = None
source: Literal["defaults", "database"] = "defaults"
provider_options: list[VoiceTTSProviderName] = Field(default_factory=list)
voice_options: dict[str, dict[str, list[VoiceTTSVoiceOption]]] = Field(default_factory=dict)
class HealthResponse(BaseModel):
status: str
service: str