124 lines
4.8 KiB
Python
124 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
from threading import Lock
|
|
|
|
from services.ai_voice_runtime_service.providers.tts import (
|
|
ElevenLabsTTSProvider,
|
|
OpenAITTSProvider,
|
|
TTSProvider,
|
|
YandexTTSProvider,
|
|
build_tts_provider,
|
|
)
|
|
from services.shared.db import get_session
|
|
from services.shared.voice_tts_config import load_effective_voice_tts_config
|
|
|
|
|
|
class RuntimeConfiguredTTSProvider(TTSProvider):
|
|
name = "dynamic"
|
|
|
|
def __init__(self, *, default_provider_name: str = "yandex") -> None:
|
|
self._default_provider_name = str(default_provider_name or "yandex").strip().lower() or "yandex"
|
|
self._provider_cache: dict[tuple[str, tuple[str | None, ...]], TTSProvider] = {}
|
|
self._lock = Lock()
|
|
|
|
def current_provider_name(self) -> str:
|
|
session = get_session()
|
|
try:
|
|
config = load_effective_voice_tts_config(session)
|
|
normalized = str(config.provider or self._default_provider_name).strip().lower()
|
|
if normalized in {"yandex", "elevenlabs", "openai"}:
|
|
return normalized
|
|
return self._default_provider_name
|
|
except Exception:
|
|
return self._default_provider_name
|
|
finally:
|
|
session.close()
|
|
|
|
def _provider_for_language(self, language: str | None) -> TTSProvider:
|
|
session = get_session()
|
|
try:
|
|
config = load_effective_voice_tts_config(session)
|
|
except Exception:
|
|
return build_tts_provider(self._default_provider_name)
|
|
finally:
|
|
session.close()
|
|
|
|
provider_name = str(config.provider or self._default_provider_name).strip().lower()
|
|
if provider_name not in {"yandex", "elevenlabs", "openai"}:
|
|
provider_name = self._default_provider_name
|
|
|
|
cache_key: tuple[str, tuple[str | None, ...]]
|
|
provider: TTSProvider
|
|
if provider_name == "yandex":
|
|
cache_key = (
|
|
provider_name,
|
|
(
|
|
config.yandex.ru.voice,
|
|
config.yandex.kz.voice,
|
|
),
|
|
)
|
|
with self._lock:
|
|
provider = self._provider_cache.get(cache_key)
|
|
if provider is None:
|
|
provider = YandexTTSProvider(
|
|
ru_voice=config.yandex.ru.voice,
|
|
kz_voice=config.yandex.kz.voice,
|
|
)
|
|
self._provider_cache[cache_key] = provider
|
|
return provider
|
|
|
|
if provider_name == "elevenlabs":
|
|
cache_key = (
|
|
provider_name,
|
|
(
|
|
config.elevenlabs.ru.voice,
|
|
config.elevenlabs.kz.voice,
|
|
config.elevenlabs.ru.model_id,
|
|
config.elevenlabs.kz.model_id,
|
|
config.elevenlabs.ru.language_code,
|
|
config.elevenlabs.kz.language_code,
|
|
),
|
|
)
|
|
with self._lock:
|
|
provider = self._provider_cache.get(cache_key)
|
|
if provider is None:
|
|
provider = ElevenLabsTTSProvider(
|
|
ru_voice=config.elevenlabs.ru.voice,
|
|
kz_voice=config.elevenlabs.kz.voice,
|
|
ru_model=config.elevenlabs.ru.model_id,
|
|
kz_model=config.elevenlabs.kz.model_id,
|
|
ru_language_code=config.elevenlabs.ru.language_code,
|
|
kz_language_code=config.elevenlabs.kz.language_code,
|
|
)
|
|
self._provider_cache[cache_key] = provider
|
|
return provider
|
|
|
|
cache_key = (
|
|
"openai",
|
|
(
|
|
config.openai.ru.voice,
|
|
config.openai.kz.voice,
|
|
config.openai.ru.model_id,
|
|
config.openai.kz.model_id,
|
|
),
|
|
)
|
|
with self._lock:
|
|
provider = self._provider_cache.get(cache_key)
|
|
if provider is None:
|
|
provider = OpenAITTSProvider(
|
|
ru_voice=config.openai.ru.voice,
|
|
kz_voice=config.openai.kz.voice,
|
|
ru_model=config.openai.ru.model_id,
|
|
kz_model=config.openai.kz.model_id,
|
|
)
|
|
self._provider_cache[cache_key] = provider
|
|
return provider
|
|
|
|
def synthesize(self, text: str, *, language: str | None = None, style_hints: dict[str, object] | None = None):
|
|
provider = self._provider_for_language(language)
|
|
return provider.synthesize(text, language=language, style_hints=style_hints)
|
|
|
|
def synthesize_chunks(self, text: str, *, language: str | None = None, style_hints: dict[str, object] | None = None):
|
|
provider = self._provider_for_language(language)
|
|
yield from provider.synthesize_chunks(text, language=language, style_hints=style_hints)
|