.
This commit is contained in:
+79
-4
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user