diff --git a/core/session.py b/core/session.py index 9631865..1c7775d 100644 --- a/core/session.py +++ b/core/session.py @@ -1840,30 +1840,50 @@ class CallSession: ) -> None: first_audio_seen = False started_monotonic = time.perf_counter() - cached_greeting = ( - self._filler_audio.pick("initial_greeting", allow_fallback=False) - if self._filler_audio is not None - else None - ) - if cached_greeting: - await self._play_cached_initial_greeting( - epoch=epoch, - greeting_text=greeting_text, - pcm_audio=cached_greeting, - started_monotonic=started_monotonic, - ) - return try: audio_chunk_count = 0 audio_byte_count = 0 - for segment_text, language_code in greeting_segments: + for segment_index, (segment_text, language_code) in enumerate(greeting_segments, start=1): + cached_segment = ( + self._filler_audio.pick( + f"initial_greeting_{segment_index}_{language_code or 'default'}", + allow_fallback=False, + ) + if self._filler_audio is not None + else None + ) + if cached_segment: + self._ensure_generation(epoch) + audio_chunk_count += 1 + audio_byte_count += len(cached_segment) + if not first_audio_seen: + first_audio_seen = True + self._log_latency( + "initial_greeting_cached_ttfa", + started_monotonic, + epoch=epoch, + message="session start -> cached initial greeting first audio", + ) + self._set_state(SessionState.ASSISTANT_SPEAKING, reason="cached initial greeting started") + LOGGER.info( + "realtime session %s initial greeting cached segment: epoch=%s index=%s language=%s bytes=%s", + self.session_id, + epoch, + segment_index, + language_code, + len(cached_segment), + ) + await self.transport.send_audio(cached_segment) + continue + async def one_shot_text_stream() -> AsyncGenerator[str, None]: yield segment_text LOGGER.info( - "realtime session %s initial greeting segment start: epoch=%s language=%s chars=%s text=%r", + "realtime session %s initial greeting segment start: epoch=%s index=%s language=%s chars=%s text=%r", self.session_id, epoch, + segment_index, language_code, len(segment_text), _preview_text(segment_text), diff --git a/main.py b/main.py index 3c922c4..52596e0 100644 --- a/main.py +++ b/main.py @@ -97,25 +97,32 @@ def _single_initial_greeting_enabled() -> bool: return raw in {"1", "true", "yes", "on"} +def _env_text_or_default(name: str, default: str) -> str: + value = os.getenv(name) + if value is None or not str(value).strip(): + return default + return str(value).strip() + + def _initial_greeting_segments() -> tuple[tuple[str, str | None], ...]: raw = str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_TEXT", "")).strip() if raw and _single_initial_greeting_enabled(): 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") or "").strip() - or ( + ru_text = _env_text_or_default( + "REALTIME_VOICE_INITIAL_GREETING_RU_TEXT", + ( "Здравствуйте! Меня зовут Айнур, я эй-ай-ассистент компании ДиджиОпс. " "Как я могу к вам обращаться и на каком языке вам удобнее продолжить: на русском или на казахском?" - ) + ), ) - kk_text = ( - str(os.getenv("REALTIME_VOICE_INITIAL_GREETING_KK_TEXT") or "").strip() - or ( + kk_text = _env_text_or_default( + "REALTIME_VOICE_INITIAL_GREETING_KK_TEXT", + ( "Сәлеметсіз бе! Менің атым Айнұр, мен ДиджиОпс компаниясының эй-ай ассистентімін. " "Сізге қалай жүгінсем болады және қай тілде сөйлескен ыңғайлы: орысша ма, қазақша ма?" - ) + ), ) segments: list[tuple[str, str | None]] = [] if ru_text: @@ -213,12 +220,32 @@ class RealtimeVoiceService: len(greeting_text), greeting_text[:120], ) - clip = await self._filler_audio.synthesize_segments(self._tts, greeting_segments) - if not clip: - LOGGER.warning("initial greeting audio preload produced empty clip") + total_bytes = 0 + for index, (segment_text, language_code) in enumerate(greeting_segments, start=1): + segment_clip = await self._filler_audio.synthesize_segments( + self._tts, + ((segment_text, language_code),), + ) + if not segment_clip: + LOGGER.warning( + "initial greeting segment preload produced empty clip: index=%s language=%s", + index, + language_code, + ) + continue + clip_key = f"initial_greeting_{index}_{language_code or 'default'}" + self._filler_audio.add_clip(clip_key, segment_clip) + total_bytes += len(segment_clip) + LOGGER.info( + "initial greeting segment preload done: key=%s language=%s bytes=%s", + clip_key, + language_code, + len(segment_clip), + ) + if total_bytes <= 0: + LOGGER.warning("initial greeting audio preload produced no segment clips") return - self._filler_audio.add_clip("initial_greeting", clip) - LOGGER.info("initial greeting audio preload done: bytes=%s", len(clip)) + LOGGER.info("initial greeting audio preload done: bytes=%s", total_bytes) except Exception: LOGGER.exception("failed to preload initial greeting audio")