Add voice name flow controls and analytics
This commit is contained in:
@@ -861,6 +861,140 @@ def test_call_started_uses_api_fallback_after_create_failure(monkeypatch, tmp_pa
|
||||
session.close()
|
||||
|
||||
|
||||
def test_voice_ai_summary_exposes_customer_name_state_for_operator(tmp_path):
|
||||
now = utc_now_iso()
|
||||
call_id = f"call_voice_summary_{tmp_path.name}"
|
||||
session_id = f"avs_voice_summary_{tmp_path.name}"
|
||||
ai_session_id = f"ais_voice_summary_{tmp_path.name}"
|
||||
interaction_id = f"int_voice_summary_{tmp_path.name}"
|
||||
|
||||
session = get_session()
|
||||
try:
|
||||
session.add(
|
||||
AsteriskCallLinkRow(
|
||||
call_id=call_id,
|
||||
linked_id=f"linked_voice_summary_{tmp_path.name}",
|
||||
queue_code="voice_support",
|
||||
queue_id="que_voice_support",
|
||||
interaction_id=interaction_id,
|
||||
caller_number="+77010001122",
|
||||
caller_name="Summary Caller",
|
||||
status="active",
|
||||
telephony_status="connected",
|
||||
claimed_by_user=None,
|
||||
claimed_at=None,
|
||||
operator_extension=None,
|
||||
channel_name="PJSIP/1001-000099",
|
||||
started_at=now,
|
||||
connected_at=now,
|
||||
ended_at=None,
|
||||
updated_at=now,
|
||||
voice_session_id=session_id,
|
||||
ai_session_id=ai_session_id,
|
||||
ai_state="handoff_required",
|
||||
ai_handoff_reason="customer requested operator",
|
||||
ai_last_model_at=now,
|
||||
voice_start_language="ru",
|
||||
customer_name_status="name_followup_required",
|
||||
customer_name_value="Айдос",
|
||||
customer_name_source="voice_start",
|
||||
customer_name_resolved_at=now,
|
||||
)
|
||||
)
|
||||
session.add(
|
||||
AISessionRow(
|
||||
session_id=ai_session_id,
|
||||
channel="voice",
|
||||
call_id=call_id,
|
||||
thread_id=None,
|
||||
interaction_id=interaction_id,
|
||||
customer_id="cus_voice_summary",
|
||||
agent_profile="voice_support",
|
||||
language="ru",
|
||||
status="handoff_required",
|
||||
summary_text="AI collected context and asked for operator handoff.",
|
||||
last_user_message_id=None,
|
||||
last_ai_message_id=None,
|
||||
handoff_reason="customer requested operator",
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
closed_at=None,
|
||||
)
|
||||
)
|
||||
session.add(
|
||||
VoiceAISessionRow(
|
||||
session_id=session_id,
|
||||
call_id=call_id,
|
||||
linked_id=f"linked_voice_summary_{tmp_path.name}",
|
||||
interaction_id=interaction_id,
|
||||
customer_id="cus_voice_summary",
|
||||
queue_id="que_voice_support",
|
||||
ai_session_id=ai_session_id,
|
||||
agent_profile="voice_support",
|
||||
language="ru",
|
||||
asr_provider="openai",
|
||||
tts_provider="yandex",
|
||||
status="handoff_requested",
|
||||
handoff_reason="customer requested operator",
|
||||
handoff_target_queue_id="que_voice_support",
|
||||
disclosure_played_at=now,
|
||||
last_user_utterance_at=now,
|
||||
last_ai_reply_at=now,
|
||||
started_at=now,
|
||||
updated_at=now,
|
||||
ended_at=None,
|
||||
voice_start_language="ru",
|
||||
customer_name_status="name_followup_required",
|
||||
customer_name_value="Айдос",
|
||||
customer_name_source="voice_start",
|
||||
customer_name_resolved_at=now,
|
||||
)
|
||||
)
|
||||
session.add_all(
|
||||
[
|
||||
VoiceTranscriptSegmentRow(
|
||||
segment_id=f"{session_id}_seg_1",
|
||||
session_id=session_id,
|
||||
call_id=call_id,
|
||||
interaction_id=interaction_id,
|
||||
sequence_no=1,
|
||||
speaker="caller",
|
||||
source_type="voice_asr",
|
||||
text="Соедините с оператором",
|
||||
confidence=0.96,
|
||||
is_final=True,
|
||||
barge_in_interrupted=False,
|
||||
payload_json="{}",
|
||||
created_at=now,
|
||||
),
|
||||
VoiceTranscriptSegmentRow(
|
||||
segment_id=f"{session_id}_seg_2",
|
||||
session_id=session_id,
|
||||
call_id=call_id,
|
||||
interaction_id=interaction_id,
|
||||
sequence_no=2,
|
||||
speaker="assistant",
|
||||
source_type="voice_policy",
|
||||
text="Сейчас переведу вас на оператора.",
|
||||
confidence=None,
|
||||
is_final=True,
|
||||
barge_in_interrupted=False,
|
||||
payload_json="{}",
|
||||
created_at=now,
|
||||
),
|
||||
]
|
||||
)
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
summary = bridge_module._voice_ai_summary_for_call(call_id)
|
||||
|
||||
assert summary is not None
|
||||
assert summary.customer_name_status == "name_followup_required"
|
||||
assert summary.customer_name_value == "Айдос"
|
||||
assert summary.customer_name_source == "voice_start"
|
||||
assert summary.voice_start_language == "ru"
|
||||
def test_call_started_re_raises_original_create_error_when_all_fallbacks_fail(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("ASTERISK_QUEUE_MAP_JSON", '{"lab":"que_lab"}')
|
||||
|
||||
@@ -3153,9 +3287,12 @@ def test_voice_ai_handoff_revives_false_ended_call_when_channel_is_resolvable(mo
|
||||
|
||||
assert result.call_id == call_id
|
||||
assert ami_calls
|
||||
assert ami_calls[0][0] == "Redirect"
|
||||
assert ami_calls[0][1]["Channel"] == "PJSIP/1001-0000077"
|
||||
assert ami_calls[0][1]["Exten"] == "2001"
|
||||
assert [call[0] for call in ami_calls[:4]] == ["Setvar", "Setvar", "Setvar", "Setvar"]
|
||||
assert ami_calls[0][1]["Variable"] == "MVPCC_START_LANGUAGE"
|
||||
assert ami_calls[3][1]["Variable"] == "MVPCC_CUSTOMER_NAME_SOURCE"
|
||||
assert ami_calls[-1][0] == "Redirect"
|
||||
assert ami_calls[-1][1]["Channel"] == "PJSIP/1001-0000077"
|
||||
assert ami_calls[-1][1]["Exten"] == "2001"
|
||||
payload = {
|
||||
"status_label": "AI передал звонок оператору",
|
||||
"customer_request_text": "Соедините меня с оператором",
|
||||
|
||||
Reference in New Issue
Block a user