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
+67 -1
View File
@@ -9,13 +9,25 @@ import services.ai_voice_runtime_service.app as runtime_module
from services.shared.core import utc_now_iso
from services.shared.db import get_session
from services.shared.models import VoiceAIStartIn
from services.shared.sql_models import VoiceAISessionRow, VoiceTranscriptSegmentRow
from services.shared.sql_models import VoiceAISessionRow, VoiceTranscriptSegmentRow, VoiceTTSSettingsRow
from services.shared.voice_tts_config import save_voice_tts_config, voice_tts_default_config
def _admin_headers() -> dict[str, str]:
return {"X-User": "admin", "X-Role": "admin"}
def _reset_voice_tts_settings() -> None:
session = get_session()
try:
row = session.execute(select(VoiceTTSSettingsRow)).scalar_one_or_none()
if row is not None:
session.delete(row)
session.commit()
finally:
session.close()
def test_create_voice_ai_session_records_greeting_without_blocking_on_orchestrator(monkeypatch):
allow_start = threading.Event()
@@ -194,6 +206,60 @@ def test_create_voice_ai_session_records_greeting_without_blocking_on_orchestrat
raise AssertionError("background voice-session start did not finish in time")
def test_create_voice_ai_session_uses_database_selected_tts_provider(monkeypatch):
_reset_voice_tts_settings()
session = get_session()
try:
payload = voice_tts_default_config().model_dump()
payload["provider"] = "elevenlabs"
save_voice_tts_config(session, payload)
finally:
session.close()
def _fake_orchestrator_request(method: str, path: str, *, payload=None, timeout=10.0):
assert method == "POST"
assert path.endswith("/start")
return {
"session_id": "ais_voice_tts_runtime",
"language": "ru",
"greeting_text": "Здравствуйте. Чем помочь?",
"disclosure_required": False,
}
monkeypatch.setattr(runtime_module, "_orchestrator_request", _fake_orchestrator_request)
client = TestClient(runtime_module.app)
response = client.post(
"/internal/voice-ai/sessions",
headers=_admin_headers(),
json={
"call_id": "call_voice_runtime_tts_provider",
"linked_id": "linked_voice_runtime_tts_provider",
"interaction_id": "int_voice_runtime_tts_provider",
"queue_id": "que_voice_runtime_tts_provider",
"caller_number": "+77010000032",
"caller_name": "Runtime Caller",
"agent_profile": "voice_support",
"language_hint": "ru",
"handoff_queue_id": "que_voice_runtime_tts_provider",
"metadata": {"queue_code": "voice_lab_ai"},
},
)
assert response.status_code == 200
session = get_session()
try:
voice_session = session.execute(
select(VoiceAISessionRow).where(VoiceAISessionRow.call_id == "call_voice_runtime_tts_provider")
).scalar_one()
assert voice_session.tts_provider == "elevenlabs"
finally:
session.close()
_reset_voice_tts_settings()
def test_mark_reply_delivered_finalizes_only_matching_pending_assistant_segment():
now = utc_now_iso()
session = get_session()