fix: handle farewells and stabilize voice responses
This commit is contained in:
@@ -52,6 +52,49 @@ SEMANTIC_ENDPOINTING_HOLD_MS = _semantic_hold_ms()
|
||||
FILLER_AUDIO_DELAY_MS = _filler_delay_ms()
|
||||
TTS_CHUNK_SOFT_MIN_CHARS = _tts_chunk_soft_min_chars()
|
||||
TTS_CHUNK_SOFT_MIN_WORDS = _tts_chunk_soft_min_words()
|
||||
_FAREWELL_MARKERS: frozenset[str] = frozenset({
|
||||
"спасибо",
|
||||
"благодарю",
|
||||
"до свидания",
|
||||
"всего доброго",
|
||||
"пока",
|
||||
"до встречи",
|
||||
"хорошего дня",
|
||||
"goodbye",
|
||||
"bye",
|
||||
})
|
||||
_FAREWELL_QUERY_MARKERS: frozenset[str] = frozenset({
|
||||
"вопрос",
|
||||
"подскаж",
|
||||
"скажи",
|
||||
"почему",
|
||||
"как",
|
||||
"что",
|
||||
"где",
|
||||
"когда",
|
||||
"можно",
|
||||
"нужно",
|
||||
"хочу",
|
||||
"мне",
|
||||
})
|
||||
FAREWELL_RESPONSE_TEXT = "Спасибо за обращение в DigiOps. Всего доброго, до свидания!"
|
||||
|
||||
|
||||
def _is_farewell_transcript(text: str) -> bool:
|
||||
normalized = _voice_text_key(text)
|
||||
return any(marker in normalized for marker in _FAREWELL_MARKERS)
|
||||
|
||||
|
||||
def _is_terminal_farewell(text: str) -> bool:
|
||||
normalized = _voice_text_key(text)
|
||||
if not any(marker in normalized for marker in _FAREWELL_MARKERS):
|
||||
return False
|
||||
if any(marker in normalized for marker in _FAREWELL_QUERY_MARKERS):
|
||||
return False
|
||||
word_count = len(re.findall(r"[^\W\d_]+(?:[-'][^\W\d_]+)*", normalized, flags=re.UNICODE))
|
||||
return word_count <= 10
|
||||
|
||||
|
||||
SEMANTIC_CONTINUATION_TOKENS = {
|
||||
"а",
|
||||
"в",
|
||||
@@ -927,6 +970,20 @@ class CallSession:
|
||||
await self._assistant_task
|
||||
await self.transport.close()
|
||||
|
||||
async def _close_after_farewell(self) -> None:
|
||||
if self._closed:
|
||||
return
|
||||
self._closed = True
|
||||
LOGGER.info(
|
||||
"realtime session %s closing transport after farewell: state=%s epoch=%s conversation_entries=%s",
|
||||
self.session_id,
|
||||
self.state.value,
|
||||
self.generation_epoch,
|
||||
len(self._conversation),
|
||||
)
|
||||
await self._cancel_live_stt_stream()
|
||||
await self.transport.close()
|
||||
|
||||
def _start_assistant_turn(
|
||||
self,
|
||||
*,
|
||||
@@ -1047,6 +1104,26 @@ class CallSession:
|
||||
)
|
||||
self._set_state(SessionState.LISTENING, reason="name collection completed")
|
||||
return
|
||||
if _is_terminal_farewell(transcript):
|
||||
LOGGER.info(
|
||||
"realtime session %s farewell response prepared: epoch=%s text=%r",
|
||||
self.session_id,
|
||||
epoch,
|
||||
_preview_text(FAREWELL_RESPONSE_TEXT),
|
||||
)
|
||||
await self._play_prepared_response(
|
||||
epoch=epoch,
|
||||
response_text=FAREWELL_RESPONSE_TEXT,
|
||||
actually_spoken_chunks=actually_spoken_chunks,
|
||||
)
|
||||
self._ensure_generation(epoch)
|
||||
self._commit_assistant_context(
|
||||
llm_generated_text=FAREWELL_RESPONSE_TEXT,
|
||||
actually_spoken_chunks=actually_spoken_chunks,
|
||||
interrupted=False,
|
||||
)
|
||||
await self._close_after_farewell()
|
||||
return
|
||||
sentence_queue = asyncio.Queue()
|
||||
self._sentence_queue = sentence_queue
|
||||
playback_task = asyncio.create_task(
|
||||
@@ -1066,6 +1143,7 @@ class CallSession:
|
||||
epoch=epoch,
|
||||
tool_name=None,
|
||||
started_monotonic=llm_started_monotonic,
|
||||
suppress=_is_farewell_transcript(transcript),
|
||||
),
|
||||
name=f"{self.session_id}-filler-delay-{epoch}",
|
||||
)
|
||||
@@ -1618,7 +1696,10 @@ class CallSession:
|
||||
epoch: int,
|
||||
tool_name: str | None,
|
||||
started_monotonic: float,
|
||||
suppress: bool = False,
|
||||
) -> None:
|
||||
if suppress:
|
||||
return
|
||||
if FILLER_AUDIO_DELAY_MS <= 0:
|
||||
self._start_filler_audio(
|
||||
epoch=epoch,
|
||||
|
||||
Reference in New Issue
Block a user