Revert "fix(voice): stop repeating failed clarifications"
This reverts commit 294d30a797.
This commit is contained in:
@@ -907,37 +907,13 @@ def _voice_is_confused_caller_text(text: str | None) -> bool:
|
||||
return any(marker in normalized for marker in confusion_markers)
|
||||
|
||||
|
||||
def _voice_is_frustrated_caller_text(text: str | None) -> bool:
|
||||
normalized = _voice_text_key(text)
|
||||
if not normalized:
|
||||
return False
|
||||
frustration_markers = (
|
||||
"я же говор",
|
||||
"я уже говор",
|
||||
"уже сказал",
|
||||
"уже сказала",
|
||||
"сколько раз",
|
||||
"ты не слыш",
|
||||
"вы не слыш",
|
||||
"не слышишь",
|
||||
"не понимаешь",
|
||||
"работай",
|
||||
"давай работай",
|
||||
)
|
||||
return any(marker in normalized for marker in frustration_markers)
|
||||
|
||||
|
||||
def _voice_recent_clarification_count(transcript_window: list[VoiceTranscriptSegmentRow]) -> int:
|
||||
markers = (
|
||||
"в двух словах",
|
||||
"о чем именно",
|
||||
"чем могу помочь",
|
||||
"график работы какого",
|
||||
"какая услуга",
|
||||
"какой филиал",
|
||||
"назовите пожалуйста",
|
||||
"назовите один вариант",
|
||||
"плохо распознал",
|
||||
"опишите пожалуйста",
|
||||
"подскажите",
|
||||
"скажите коротко",
|
||||
@@ -952,12 +928,6 @@ def _voice_recent_clarification_count(transcript_window: list[VoiceTranscriptSeg
|
||||
if segment.speaker != "assistant":
|
||||
continue
|
||||
normalized = _voice_text_key(segment.text)
|
||||
if normalized.startswith("здравствуйте") and (
|
||||
"коротко расскажите" in normalized
|
||||
or "назовите пожалуйста ваше имя" in normalized
|
||||
or "подскажите пожалуйста чем помочь" in normalized
|
||||
):
|
||||
continue
|
||||
if any(marker in normalized for marker in markers):
|
||||
count += 1
|
||||
return count
|
||||
@@ -1146,12 +1116,6 @@ def _voice_confusion_prompt(language: str, caller_texts: list[str]) -> str:
|
||||
return "Подскажите точнее: график работы, статус заявки, тариф или оператор."
|
||||
|
||||
|
||||
def _voice_repair_prompt(language: str) -> str:
|
||||
if language == "kz":
|
||||
return "Daуыs nashar tanyldy. Bir нұсқаны ғана айтыңыз: jumys uaqyty, mekenjai, tarif, otinish nemese operator."
|
||||
return "Плохо распознал запрос. Назовите один вариант: график работы, адрес, тариф, заявка или оператор."
|
||||
|
||||
|
||||
def _voice_loop_handoff(language: str) -> tuple[str, str, str]:
|
||||
if language == "kz":
|
||||
return (
|
||||
@@ -1998,9 +1962,8 @@ def _voice_decision(
|
||||
recent_caller_window = caller_texts[-3:]
|
||||
low_signal_count = sum(1 for text in recent_caller_window if _voice_is_low_signal_caller_text(text))
|
||||
caller_confused = _voice_is_confused_caller_text(normalized)
|
||||
caller_frustrated = _voice_is_frustrated_caller_text(normalized)
|
||||
if clarification_count >= 4 or (
|
||||
clarification_count >= 3 and (caller_confused or caller_frustrated or low_signal_count >= 2 or repeated_reply_count >= 2)
|
||||
clarification_count >= 3 and (caller_confused or low_signal_count >= 2 or repeated_reply_count >= 2)
|
||||
):
|
||||
reply_text, handoff_reason, summary_text = _voice_loop_handoff(language)
|
||||
return {
|
||||
@@ -2017,32 +1980,6 @@ def _voice_decision(
|
||||
"latency_ms": 1,
|
||||
}
|
||||
|
||||
if not kb_results and (
|
||||
caller_frustrated
|
||||
or (
|
||||
clarification_count >= 2
|
||||
and repeated_reply_count >= 1
|
||||
and not _voice_has_service_topic(normalized)
|
||||
)
|
||||
):
|
||||
decision = {
|
||||
"language": language,
|
||||
"intent": "clarification",
|
||||
"reply_text": _voice_repair_prompt(language),
|
||||
"confidence": 0.5,
|
||||
"needs_handoff": False,
|
||||
"handoff_reason": None,
|
||||
"case_action": "keep_open",
|
||||
"kb_refs": [],
|
||||
"summary_text": "AI переключился в repair-mode после неудачных уточнений и попросил выбрать один короткий вариант.",
|
||||
"model": "voice_policy_repair",
|
||||
"latency_ms": 1,
|
||||
}
|
||||
if v2_metadata:
|
||||
decision["reply_text"] = _voice_compact_reply_text(decision["reply_text"], language=language)
|
||||
decision["metadata"] = {**v2_metadata, "reply_phase": "final"}
|
||||
return decision
|
||||
|
||||
if not kb_results and _voice_is_off_domain_request(normalized):
|
||||
reply_text, summary_text = _voice_off_domain_reply(language)
|
||||
decision = {
|
||||
|
||||
@@ -1247,60 +1247,6 @@ def test_voice_decision_handoffs_after_repeated_clarification_loop():
|
||||
assert "нескольких попыток" in decision["handoff_reason"].lower()
|
||||
|
||||
|
||||
def test_voice_decision_uses_repair_prompt_after_repeated_unknown_request():
|
||||
transcript_window = [
|
||||
SimpleNamespace(speaker="assistant", text=voice_module._voice_greeting("ru"), sequence_no=1),
|
||||
SimpleNamespace(speaker="caller", text=_u(r"\u041d\u0443 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043a \u0432\u0430\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f."), sequence_no=2),
|
||||
SimpleNamespace(speaker="assistant", text=_u(r"\u0415\u0440\u043d\u0443\u0440. \u0427\u0435\u043c \u043c\u043e\u0433\u0443 \u043f\u043e\u043c\u043e\u0447\u044c?"), sequence_no=3),
|
||||
SimpleNamespace(speaker="caller", text=_u(r"\u041c\u043d\u0435 \u043d\u0430\u0434\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0437-"), sequence_no=4),
|
||||
SimpleNamespace(speaker="assistant", text=_u(r"\u0415\u0440\u043d\u0443\u0440, \u043e \u0447\u0435\u043c \u0438\u043c\u0435\u043d\u043d\u043e \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c?"), sequence_no=5),
|
||||
SimpleNamespace(speaker="caller", text=_u(r"\u042f \u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u044e, \u043c\u043d\u0435 \u043d\u0430\u0434\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u0433\u0434\u0435--"), sequence_no=6),
|
||||
]
|
||||
|
||||
decision = voice_module._voice_decision(
|
||||
language="ru",
|
||||
customer=None,
|
||||
interaction=SimpleNamespace(interaction_id="int_voice_repair"),
|
||||
transcript_text=_u(r"\u042f \u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u044e, \u043c\u043d\u0435 \u043d\u0430\u0434\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u0433\u0434\u0435--"),
|
||||
transcript_window=transcript_window,
|
||||
kb_results=[],
|
||||
disclosure_required=False,
|
||||
request_metadata={"voice_v2_enabled": True, "response_plan_id": "rsp_repair"},
|
||||
)
|
||||
|
||||
normalized = decision["reply_text"].lower()
|
||||
assert decision["model"] == "voice_policy_repair"
|
||||
assert decision["needs_handoff"] is False
|
||||
assert "назовите один вариант" in normalized
|
||||
assert "график работы" in normalized
|
||||
assert "оператор" in normalized
|
||||
assert "о чем именно" not in normalized
|
||||
|
||||
|
||||
def test_voice_decision_handoffs_after_frustrated_repair_loop():
|
||||
transcript_window = [
|
||||
SimpleNamespace(speaker="assistant", text=voice_module._voice_greeting("ru"), sequence_no=1),
|
||||
SimpleNamespace(speaker="assistant", text=_u(r"\u0415\u0440\u043d\u0443\u0440. \u0427\u0435\u043c \u043c\u043e\u0433\u0443 \u043f\u043e\u043c\u043e\u0447\u044c?"), sequence_no=2),
|
||||
SimpleNamespace(speaker="assistant", text=_u(r"\u0415\u0440\u043d\u0443\u0440, \u043e \u0447\u0435\u043c \u0438\u043c\u0435\u043d\u043d\u043e \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c?"), sequence_no=3),
|
||||
SimpleNamespace(speaker="assistant", text=_u(r"\u041f\u043b\u043e\u0445\u043e \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043b \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u0430\u0437\u043e\u0432\u0438\u0442\u0435 \u043e\u0434\u0438\u043d \u0432\u0430\u0440\u0438\u0430\u043d\u0442: \u0433\u0440\u0430\u0444\u0438\u043a \u0440\u0430\u0431\u043e\u0442\u044b, \u0430\u0434\u0440\u0435\u0441, \u0442\u0430\u0440\u0438\u0444, \u0437\u0430\u044f\u0432\u043a\u0430 \u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440."), sequence_no=4),
|
||||
]
|
||||
|
||||
decision = voice_module._voice_decision(
|
||||
language="ru",
|
||||
customer=None,
|
||||
interaction=SimpleNamespace(interaction_id="int_voice_repair_handoff"),
|
||||
transcript_text=_u(r"\u0422\u0430\u043a \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0439."),
|
||||
transcript_window=transcript_window,
|
||||
kb_results=[],
|
||||
disclosure_required=False,
|
||||
request_metadata={"voice_v2_enabled": True, "response_plan_id": "rsp_repair_handoff"},
|
||||
)
|
||||
|
||||
assert decision["intent"] == "handoff_request"
|
||||
assert decision["needs_handoff"] is True
|
||||
assert "оператор" in decision["reply_text"].lower()
|
||||
|
||||
|
||||
def test_voice_kb_search_matches_relaxed_phrase_and_returns_kb_answer():
|
||||
query = _u(r"\u0425\u043e\u0447\u0443 \u0443\u0437\u043d\u0430\u0442\u044c \u0442\u0430\u0440\u0438\u0444 relaxbasicx")
|
||||
seed_kb_article(
|
||||
|
||||
Reference in New Issue
Block a user