This commit is contained in:
Konturai DevOps
2026-05-02 00:48:40 +05:00
parent 676d7155bd
commit 8a83a4d575
6 changed files with 501 additions and 63 deletions
+79 -4
View File
@@ -245,6 +245,54 @@ def _preview_text(text: str, *, limit: int = 160) -> str:
return f"{normalized[:limit]}..."
_KAZAKH_SPECIFIC_LETTERS = set("әғқңөұүһі")
_RUSSIAN_SPECIFIC_LETTERS = set("ыэъё")
def _detect_session_language(text: str) -> str | None:
normalized = str(text or "").strip().lower()
if not normalized:
return None
has_kazakh = any(ch in _KAZAKH_SPECIFIC_LETTERS for ch in normalized)
if has_kazakh:
return "kk"
has_russian = any(ch in _RUSSIAN_SPECIFIC_LETTERS for ch in normalized)
if has_russian:
return "ru"
cyrillic_chars = sum(1 for ch in normalized if "а" <= ch <= "я" or ch == "ё")
if cyrillic_chars >= 2:
return "ru"
return None
_TTS_LANGUAGE_CODE_MAP = {
"ru": "ru",
"kk": "kk",
}
_STT_YANDEX_LANGUAGE_MAP = {
"ru": "ru-RU",
"kk": "kk-KZ",
}
_STT_ELEVENLABS_LANGUAGE_MAP = {
"ru": "rus",
"kk": "kaz",
}
def _tts_language_for(session_language: str | None) -> str | None:
if not session_language:
return None
return _TTS_LANGUAGE_CODE_MAP.get(session_language.lower())
def _stt_language_for(session_language: str | None) -> str | None:
if not session_language:
return None
return session_language.lower() if session_language.lower() in {"ru", "kk"} else None
def _audio_duration_ms(audio_bytes: bytes, *, sample_rate_hz: int) -> int:
if not audio_bytes or sample_rate_hz <= 0:
return 0
@@ -993,6 +1041,7 @@ class CallSession:
self._personalized_greeting_template = DEFAULT_PERSONALIZED_GREETING_TEMPLATE
self._live_stt_stream: BaseSTTStream | None = None
self._latest_partial_transcript = ""
self._session_language: str | None = None
self._default_vad_silence_timeout_ms = getattr(self._vad, "default_speech_end_silence_ms", 550)
self._semantic_hold_silence_timeout_ms = max(self._default_vad_silence_timeout_ms, SEMANTIC_ENDPOINTING_HOLD_MS)
LOGGER.info(
@@ -1235,6 +1284,18 @@ class CallSession:
)
self._active_user_transcript = transcript
if self._session_language is None:
detected_language = _detect_session_language(transcript)
if detected_language:
self._session_language = detected_language
LOGGER.info(
"realtime session %s language locked: epoch=%s language=%s transcript=%r",
self.session_id,
epoch,
detected_language,
_preview_text(transcript),
)
LOGGER.info(
"realtime session %s transcript accepted: epoch=%s chars=%s text=%r",
self.session_id,
@@ -1334,7 +1395,11 @@ class CallSession:
),
name=f"{self.session_id}-filler-delay-{epoch}",
)
async for event in self._llm.generate_stream(transcript, self._build_llm_context()):
async for event in self._llm.generate_stream(
transcript,
self._build_llm_context(),
language_code=self._session_language,
):
self._ensure_generation(epoch)
if event.type == "tool_call_start":
LOGGER.info(
@@ -1546,7 +1611,11 @@ class CallSession:
await self._stt.transcribe(
audio_bytes,
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
language_code=self._name_capture_language_code() if self._awaiting_customer_name else None,
language_code=(
self._name_capture_language_code()
if self._awaiting_customer_name
else _stt_language_for(self._session_language)
),
force_batch=self._awaiting_customer_name,
)
).strip()
@@ -1825,7 +1894,8 @@ class CallSession:
sentence_queue=sentence_queue,
started_holder=tts_started_monotonic,
actually_spoken_chunks=actually_spoken_chunks,
)
),
language_code=_tts_language_for(self._session_language),
):
self._ensure_generation(epoch)
if not audio_chunk:
@@ -2061,6 +2131,7 @@ class CallSession:
live_stt_stream = await self._stt.start_stream(
partial_callback=self._handle_partial_transcript,
keyterms=None,
language_code=_stt_language_for(self._session_language),
)
except Exception:
LOGGER.exception("realtime session %s failed to start live STT stream", self.session_id)
@@ -2137,7 +2208,11 @@ class CallSession:
return await self._stt.transcribe(
utterance_audio,
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
language_code=self._name_capture_language_code() if self._awaiting_customer_name else None,
language_code=(
self._name_capture_language_code()
if self._awaiting_customer_name
else _stt_language_for(self._session_language)
),
force_batch=self._awaiting_customer_name,
)