diff --git a/app/services/conversation.py b/app/services/conversation.py index 0174d98..aa35ff9 100644 --- a/app/services/conversation.py +++ b/app/services/conversation.py @@ -38,7 +38,8 @@ BOUNDARY_TRIGGER_RE = re.compile( r"price|pricing|how\s+much|\bcost\b|discount|cheaper|expensive|\bfee\b|" r"quote|quotation|shipping\s+(fee|cost|time)|freight|tariff|customs\s+fee|" r"best\s+offer|any\s+offer|free\s+shipping|" - r"sample|certificat|\bmoq\b|container\s+loading|" + r"sample|certificat|\bmoq\b|minimum\s+order|min\s+order|" + r"container\s+loading|fit\s+in|per\s+container|warranty|质保|保修|" r"book(ing)?\s|reserv|arrange|" r"delivery|lead\s+time|arriv|" r"how\s+long\s+(does|will|would|to).*(take|arriv|deliver|ship)|" @@ -591,8 +592,7 @@ class ConversationManager: "绝对禁止输出任何号码或邮箱。") else: contact_note = ("⚠️ 客户正在索要我方联系方式(最高意向信号)。请逐字使用这句指路:" - "\"Just tap the WhatsApp button at the top of this chat — " - "our manager will reply within 12 hours!\"(邮箱同理指 Email 按钮)。" + f"\"{NO_CONTACT_WEB}\"(邮箱同理指 Email 按钮)。" "绝对禁止口头报出任何号码或邮箱。") if not raw_info: diff --git a/tests/test_boundary_filter.py b/tests/test_boundary_filter.py index e68247a..f3c65e3 100644 --- a/tests/test_boundary_filter.py +++ b/tests/test_boundary_filter.py @@ -329,3 +329,16 @@ def test_no_auto_wording_left_in_any_pool(): for t in (pool if isinstance(pool, list) else [pool]): assert "cars" not in t.lower(), f"{name}: {t}" assert "什么车" not in t, f"{name}: {t}" + + +def test_arabic_echo_exemption_consistent(): + ar_num = "".join(chr(c) for c in + (0x0669, 0x0666, 0x0666, 0x0665, 0x0660, 0x0661, + 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667)) # 966501234567 + # 阿语回显豁免一致性锁定(Task 6 质量审查): 客户用阿语数字留号,AI 无论 + # 回显阿语还是 ASCII 形态都豁免——两侧均经 digits_only(内含 translate)。 + # 阿语数字用码位构造,避免源文件编码事故。 + hist = [{"role": "user", "content": "my whatsapp is " + ar_num}] + assert not no_contact_value("Got it — messaging you at " + ar_num, hist) + assert not no_contact_value("Got it — messaging you at +966501234567", hist) + assert no_contact_value("Reach me at 11987654321", hist) # 不同号(11位)仍拦 diff --git a/tests/test_lead_email_trigger.py b/tests/test_lead_email_trigger.py index cfbdfc8..93b090a 100644 --- a/tests/test_lead_email_trigger.py +++ b/tests/test_lead_email_trigger.py @@ -43,7 +43,7 @@ class FakeAI: INTERESTED = { - "intent_level": "interested", "reasoning": "预算国家车型齐全", + "intent_level": "interested", "reasoning": "预算国家品类齐全", "contact_info": {}, "info_sufficient": True, } @@ -487,7 +487,7 @@ def test_reminder_boundary_covers_delivery_and_arrangement(): {}, "my budget is 20000, any recommendation?", []) -def test_reminder_no_boundary_on_normal_car_questions(): +def test_reminder_no_boundary_on_normal_product_questions(): # 规格/配置/库存类正常问题不得误触发 assert "职能边界" not in ConversationManager._build_context_reminder( {}, "what is the pressure rating of the PE100 pipe?", []) @@ -562,7 +562,7 @@ def test_clean_stream_passes_through(async_db, monkeypatch): (manager, conv), _ = _setup(async_db, monkeypatch, ai=FakeAI()) events = [] async def run(): - async for e in manager.stream_process_message(conv.session_id, "what cars?"): + async for e in manager.stream_process_message(conv.session_id, "what pipes?"): events.append(e) asyncio.run(run()) streamed = "".join(e.get("content", "") for e in events if e["type"] == "stream_chunk") @@ -613,7 +613,7 @@ def test_sentence_gating_clean_multi_sentence_passthrough(async_db, monkeypatch) (manager, conv), _ = _setup(async_db, monkeypatch, ai=TwoSentenceAI()) events = [] async def run(): - async for e in manager.stream_process_message(conv.session_id, "what cars?"): + async for e in manager.stream_process_message(conv.session_id, "what pipes?"): events.append(e) asyncio.run(run()) streamed = "".join(e.get("content", "") for e in events if e["type"] == "stream_chunk")