This commit is contained in:
Konturai DevOps
2026-05-02 01:54:00 +05:00
parent 00d9b241f0
commit af2e78ce20
4 changed files with 70 additions and 35 deletions
+19 -1
View File
@@ -107,10 +107,28 @@ class FillerAudioLibrary:
segments: Iterable[tuple[str, str | None]],
) -> bytes:
clip = bytearray()
for text, language_code in segments:
for i, (text, language_code) in enumerate(segments):
LOGGER.info(
"synthesize_segments: starting segment %s language=%s text=%r",
i,
language_code,
text[:60],
)
segment = await self._synthesize_clip(tts, text, language_code=language_code)
if segment:
clip.extend(segment)
LOGGER.info(
"synthesize_segments: completed segment %s bytes=%s total_bytes=%s",
i,
len(segment),
len(clip),
)
else:
LOGGER.warning(
"synthesize_segments: segment %s produced NO audio; language=%s",
i,
language_code,
)
return bytes(clip)
def _load_from_files(self) -> None:
+16
View File
@@ -1868,6 +1868,7 @@ class CallSession:
len(segment_text),
_preview_text(segment_text),
)
audio_segment_chunk_count = 0
async for audio_chunk in self._tts.synthesize_stream(
one_shot_text_stream(),
language_code=language_code,
@@ -1875,6 +1876,7 @@ class CallSession:
self._ensure_generation(epoch)
if not audio_chunk:
continue
audio_segment_chunk_count += 1
audio_chunk_count += 1
audio_byte_count += len(audio_chunk)
if not first_audio_seen:
@@ -1887,6 +1889,20 @@ class CallSession:
)
self._set_state(SessionState.ASSISTANT_SPEAKING, reason="initial greeting started")
await self.transport.send_audio(audio_chunk)
if audio_segment_chunk_count == 0:
LOGGER.warning(
"realtime session %s initial greeting segment produced NO audio: language=%s",
self.session_id,
language_code,
)
else:
LOGGER.info(
"realtime session %s initial greeting segment completed: language=%s chunks=%s",
self.session_id,
language_code,
audio_segment_chunk_count,
)
await self.transport.flush_audio()
self._ensure_generation(epoch)
LOGGER.info(
+8 -12
View File
@@ -103,24 +103,20 @@ def _initial_greeting_segments() -> tuple[tuple[str, str | None], ...]:
language = str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_LANGUAGE_CODE", "")).strip() or None
return ((raw, language),)
ru_text = str(
os.getenv(
"REALTIME_VOICE_INITIAL_GREETING_RU_TEXT",
(
ru_text = (
str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_RU_TEXT") or "").strip()
or (
"Здравствуйте! Меня зовут Айнур, я эй-ай-ассистент компании ДиджиОпс. "
"Как я могу к вам обращаться и на каком языке вам удобнее продолжить: на русском или на казахском?"
),
)
).strip()
kk_text = str(
os.getenv(
"REALTIME_VOICE_INITIAL_GREETING_KK_TEXT",
(
)
kk_text = (
str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_KK_TEXT") or "").strip()
or (
"Сәлеметсіз бе! Менің атым Айнұр, мен ДиджиОпс компаниясының эй-ай ассистентімін. "
"Сізге қалай жүгінсем болады және қай тілде сөйлескен ыңғайлы: орысша ма, қазақша ма?"
),
)
).strip()
)
segments: list[tuple[str, str | None]] = []
if ru_text:
segments.append((ru_text, "ru"))
+23 -18
View File
@@ -192,7 +192,11 @@ class ElevenLabsTTS(BaseTTS):
if not self._voice_id:
raise RuntimeError("ELEVENLABS_TTS_VOICE_ID is required for ElevenLabs TTS")
effective_language_code = (str(language_code).strip() if language_code else "") or self._language_code
# If language_code is explicitly provided, use it.
# If it's None, use the instance default self._language_code.
# To trigger auto-detection, language_code should be an empty string or the default should be None.
effective_language_code = language_code if language_code is not None else self._language_code
if self._resolved_transport_mode() == "http_stream":
async for audio_chunk in self._synthesize_http_stream(
text_stream,
@@ -234,7 +238,7 @@ class ElevenLabsTTS(BaseTTS):
self._output_format,
self._provider_sample_rate_hz,
self._target_sample_rate_hz,
language_code,
language_code or "auto",
self._auto_mode,
)
try:
@@ -297,13 +301,14 @@ class ElevenLabsTTS(BaseTTS):
if audio_chunk:
yield audio_chunk
if self._is_error_payload(payload):
error_detail = self._format_error_payload(payload)
LOGGER.error(
"ElevenLabs TTS error payload: voice_id=%s model=%s payload=%s",
"ElevenLabs TTS error payload: voice_id=%s model=%s error=%s",
self._voice_id,
self._model_id,
self._format_error_payload(payload),
error_detail,
)
raise RuntimeError(self._format_error_payload(payload))
raise RuntimeError(error_detail)
if bool(payload.get("isFinal")) or bool(payload.get("is_final")):
LOGGER.info(
"ElevenLabs TTS final payload: voice_id=%s model=%s chunks=%s "
@@ -327,9 +332,9 @@ class ElevenLabsTTS(BaseTTS):
except asyncio.TimeoutError as exc:
raise RuntimeError("ElevenLabs TTS WebSocket request timed out") from exc
except WebSocketException as exc:
raise RuntimeError("ElevenLabs TTS WebSocket stream failed") from exc
raise RuntimeError(f"ElevenLabs TTS WebSocket stream failed: {exc}") from exc
except OSError as exc:
raise RuntimeError("ElevenLabs TTS WebSocket connection failed") from exc
raise RuntimeError(f"ElevenLabs TTS WebSocket connection failed: {exc}") from exc
async def _synthesize_http_stream(
self,
@@ -364,7 +369,7 @@ class ElevenLabsTTS(BaseTTS):
self._output_format,
self._provider_sample_rate_hz,
self._target_sample_rate_hz,
language_code,
language_code or "auto",
)
try:
@@ -389,9 +394,9 @@ class ElevenLabsTTS(BaseTTS):
async with session.post(url, headers=headers, json=payload) as response:
if response.status >= 400:
payload_text = await response.text()
raise RuntimeError(
f"ElevenLabs TTS HTTP {response.status}: {payload_text[:300]}"
)
error_msg = f"ElevenLabs TTS HTTP {response.status}: {payload_text[:300]}"
LOGGER.error(error_msg)
raise RuntimeError(error_msg)
async for audio_chunk in response.content.iter_chunked(4096):
if not audio_chunk:
continue
@@ -439,7 +444,7 @@ class ElevenLabsTTS(BaseTTS):
except asyncio.TimeoutError as exc:
raise RuntimeError("ElevenLabs TTS HTTP stream timed out") from exc
except aiohttp.ClientError as exc:
raise RuntimeError("ElevenLabs TTS HTTP stream failed") from exc
raise RuntimeError(f"ElevenLabs TTS HTTP stream failed: {exc}") from exc
LOGGER.info(
"ElevenLabs TTS HTTP stream completed: voice_id=%s model=%s requests=%s chunks=%s "
@@ -462,9 +467,9 @@ class ElevenLabsTTS(BaseTTS):
"sync_alignment": "false",
"apply_text_normalization": self._apply_text_normalization,
}
effective_language = (str(language_code).strip() if language_code else "") or self._language_code
if effective_language:
query["language_code"] = effective_language
# Use provided language_code or fallback to None for auto-detection
if language_code:
query["language_code"] = language_code
encoded_voice_id = quote(self._voice_id, safe="")
return f"{self._ws_base}/v1/text-to-speech/{encoded_voice_id}/stream-input?{urlencode(query)}"
@@ -482,9 +487,9 @@ class ElevenLabsTTS(BaseTTS):
"voice_settings": self._voice_settings,
"apply_text_normalization": self._apply_text_normalization,
}
effective_language = (str(language_code).strip() if language_code else "") or self._language_code
if effective_language:
payload["language_code"] = effective_language
# Use provided language_code or fallback to None for auto-detection
if language_code:
payload["language_code"] = language_code
return payload
def _resolved_transport_mode(self) -> str: