gemma
This commit is contained in:
+19
-1
@@ -107,10 +107,28 @@ class FillerAudioLibrary:
|
|||||||
segments: Iterable[tuple[str, str | None]],
|
segments: Iterable[tuple[str, str | None]],
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
clip = bytearray()
|
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)
|
segment = await self._synthesize_clip(tts, text, language_code=language_code)
|
||||||
if segment:
|
if segment:
|
||||||
clip.extend(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)
|
return bytes(clip)
|
||||||
|
|
||||||
def _load_from_files(self) -> None:
|
def _load_from_files(self) -> None:
|
||||||
|
|||||||
@@ -1868,6 +1868,7 @@ class CallSession:
|
|||||||
len(segment_text),
|
len(segment_text),
|
||||||
_preview_text(segment_text),
|
_preview_text(segment_text),
|
||||||
)
|
)
|
||||||
|
audio_segment_chunk_count = 0
|
||||||
async for audio_chunk in self._tts.synthesize_stream(
|
async for audio_chunk in self._tts.synthesize_stream(
|
||||||
one_shot_text_stream(),
|
one_shot_text_stream(),
|
||||||
language_code=language_code,
|
language_code=language_code,
|
||||||
@@ -1875,6 +1876,7 @@ class CallSession:
|
|||||||
self._ensure_generation(epoch)
|
self._ensure_generation(epoch)
|
||||||
if not audio_chunk:
|
if not audio_chunk:
|
||||||
continue
|
continue
|
||||||
|
audio_segment_chunk_count += 1
|
||||||
audio_chunk_count += 1
|
audio_chunk_count += 1
|
||||||
audio_byte_count += len(audio_chunk)
|
audio_byte_count += len(audio_chunk)
|
||||||
if not first_audio_seen:
|
if not first_audio_seen:
|
||||||
@@ -1887,6 +1889,20 @@ class CallSession:
|
|||||||
)
|
)
|
||||||
self._set_state(SessionState.ASSISTANT_SPEAKING, reason="initial greeting started")
|
self._set_state(SessionState.ASSISTANT_SPEAKING, reason="initial greeting started")
|
||||||
await self.transport.send_audio(audio_chunk)
|
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()
|
await self.transport.flush_audio()
|
||||||
self._ensure_generation(epoch)
|
self._ensure_generation(epoch)
|
||||||
LOGGER.info(
|
LOGGER.info(
|
||||||
|
|||||||
@@ -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
|
language = str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_LANGUAGE_CODE", "")).strip() or None
|
||||||
return ((raw, language),)
|
return ((raw, language),)
|
||||||
|
|
||||||
ru_text = str(
|
ru_text = (
|
||||||
os.getenv(
|
str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_RU_TEXT") or "").strip()
|
||||||
"REALTIME_VOICE_INITIAL_GREETING_RU_TEXT",
|
or (
|
||||||
(
|
"Здравствуйте! Меня зовут Айнур, я эй-ай-ассистент компании ДиджиОпс. "
|
||||||
"Здравствуйте! Меня зовут Айнур, я эй-ай-ассистент компании ДиджиОпс. "
|
"Как я могу к вам обращаться и на каком языке вам удобнее продолжить: на русском или на казахском?"
|
||||||
"Как я могу к вам обращаться и на каком языке вам удобнее продолжить: на русском или на казахском?"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
).strip()
|
)
|
||||||
kk_text = str(
|
kk_text = (
|
||||||
os.getenv(
|
str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_KK_TEXT") or "").strip()
|
||||||
"REALTIME_VOICE_INITIAL_GREETING_KK_TEXT",
|
or (
|
||||||
(
|
"Сәлеметсіз бе! Менің атым Айнұр, мен ДиджиОпс компаниясының эй-ай ассистентімін. "
|
||||||
"Сәлеметсіз бе! Менің атым Айнұр, мен ДиджиОпс компаниясының эй-ай ассистентімін. "
|
"Сізге қалай жүгінсем болады және қай тілде сөйлескен ыңғайлы: орысша ма, қазақша ма?"
|
||||||
"Сізге қалай жүгінсем болады және қай тілде сөйлескен ыңғайлы: орысша ма, қазақша ма?"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
).strip()
|
)
|
||||||
segments: list[tuple[str, str | None]] = []
|
segments: list[tuple[str, str | None]] = []
|
||||||
if ru_text:
|
if ru_text:
|
||||||
segments.append((ru_text, "ru"))
|
segments.append((ru_text, "ru"))
|
||||||
|
|||||||
+23
-18
@@ -192,7 +192,11 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
if not self._voice_id:
|
if not self._voice_id:
|
||||||
raise RuntimeError("ELEVENLABS_TTS_VOICE_ID is required for ElevenLabs TTS")
|
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":
|
if self._resolved_transport_mode() == "http_stream":
|
||||||
async for audio_chunk in self._synthesize_http_stream(
|
async for audio_chunk in self._synthesize_http_stream(
|
||||||
text_stream,
|
text_stream,
|
||||||
@@ -234,7 +238,7 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
self._output_format,
|
self._output_format,
|
||||||
self._provider_sample_rate_hz,
|
self._provider_sample_rate_hz,
|
||||||
self._target_sample_rate_hz,
|
self._target_sample_rate_hz,
|
||||||
language_code,
|
language_code or "auto",
|
||||||
self._auto_mode,
|
self._auto_mode,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
@@ -297,13 +301,14 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
if audio_chunk:
|
if audio_chunk:
|
||||||
yield audio_chunk
|
yield audio_chunk
|
||||||
if self._is_error_payload(payload):
|
if self._is_error_payload(payload):
|
||||||
|
error_detail = self._format_error_payload(payload)
|
||||||
LOGGER.error(
|
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._voice_id,
|
||||||
self._model_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")):
|
if bool(payload.get("isFinal")) or bool(payload.get("is_final")):
|
||||||
LOGGER.info(
|
LOGGER.info(
|
||||||
"ElevenLabs TTS final payload: voice_id=%s model=%s chunks=%s "
|
"ElevenLabs TTS final payload: voice_id=%s model=%s chunks=%s "
|
||||||
@@ -327,9 +332,9 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
except asyncio.TimeoutError as exc:
|
except asyncio.TimeoutError as exc:
|
||||||
raise RuntimeError("ElevenLabs TTS WebSocket request timed out") from exc
|
raise RuntimeError("ElevenLabs TTS WebSocket request timed out") from exc
|
||||||
except WebSocketException as 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:
|
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(
|
async def _synthesize_http_stream(
|
||||||
self,
|
self,
|
||||||
@@ -364,7 +369,7 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
self._output_format,
|
self._output_format,
|
||||||
self._provider_sample_rate_hz,
|
self._provider_sample_rate_hz,
|
||||||
self._target_sample_rate_hz,
|
self._target_sample_rate_hz,
|
||||||
language_code,
|
language_code or "auto",
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -389,9 +394,9 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
async with session.post(url, headers=headers, json=payload) as response:
|
async with session.post(url, headers=headers, json=payload) as response:
|
||||||
if response.status >= 400:
|
if response.status >= 400:
|
||||||
payload_text = await response.text()
|
payload_text = await response.text()
|
||||||
raise RuntimeError(
|
error_msg = f"ElevenLabs TTS HTTP {response.status}: {payload_text[:300]}"
|
||||||
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):
|
async for audio_chunk in response.content.iter_chunked(4096):
|
||||||
if not audio_chunk:
|
if not audio_chunk:
|
||||||
continue
|
continue
|
||||||
@@ -439,7 +444,7 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
except asyncio.TimeoutError as exc:
|
except asyncio.TimeoutError as exc:
|
||||||
raise RuntimeError("ElevenLabs TTS HTTP stream timed out") from exc
|
raise RuntimeError("ElevenLabs TTS HTTP stream timed out") from exc
|
||||||
except aiohttp.ClientError as 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(
|
LOGGER.info(
|
||||||
"ElevenLabs TTS HTTP stream completed: voice_id=%s model=%s requests=%s chunks=%s "
|
"ElevenLabs TTS HTTP stream completed: voice_id=%s model=%s requests=%s chunks=%s "
|
||||||
@@ -462,9 +467,9 @@ class ElevenLabsTTS(BaseTTS):
|
|||||||
"sync_alignment": "false",
|
"sync_alignment": "false",
|
||||||
"apply_text_normalization": self._apply_text_normalization,
|
"apply_text_normalization": self._apply_text_normalization,
|
||||||
}
|
}
|
||||||
effective_language = (str(language_code).strip() if language_code else "") or self._language_code
|
# Use provided language_code or fallback to None for auto-detection
|
||||||
if effective_language:
|
if language_code:
|
||||||
query["language_code"] = effective_language
|
query["language_code"] = language_code
|
||||||
encoded_voice_id = quote(self._voice_id, safe="")
|
encoded_voice_id = quote(self._voice_id, safe="")
|
||||||
return f"{self._ws_base}/v1/text-to-speech/{encoded_voice_id}/stream-input?{urlencode(query)}"
|
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,
|
"voice_settings": self._voice_settings,
|
||||||
"apply_text_normalization": self._apply_text_normalization,
|
"apply_text_normalization": self._apply_text_normalization,
|
||||||
}
|
}
|
||||||
effective_language = (str(language_code).strip() if language_code else "") or self._language_code
|
# Use provided language_code or fallback to None for auto-detection
|
||||||
if effective_language:
|
if language_code:
|
||||||
payload["language_code"] = effective_language
|
payload["language_code"] = language_code
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def _resolved_transport_mode(self) -> str:
|
def _resolved_transport_mode(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user