feat: 会话编排建材化+阿语号码转ASCII+12小时话术跨层同步
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -158,12 +158,12 @@ def test_asks_contact_detects_production_log_phrasings():
|
||||
assert asks_contact("Drop yours too and our manager will send you the full quote!")
|
||||
assert asks_contact("留个WhatsApp或者邮箱吧?")
|
||||
assert asks_contact("你WhatsApp多少?")
|
||||
assert asks_contact("你给我个联系方式,我让客户经理给你推几个车型。")
|
||||
assert asks_contact("你给我个联系方式,我让客户经理给你推几个产品方案。")
|
||||
|
||||
|
||||
def test_asks_contact_clean_phrasings_pass():
|
||||
assert not asks_contact("Got your number, thanks!") # 确认,非问句
|
||||
assert not asks_contact("Just tap the WhatsApp button at the top of this chat — our manager replies fast!")
|
||||
assert not asks_contact("Just tap the WhatsApp button at the top of this chat — our manager will reply within 12 hours!")
|
||||
assert not asks_contact("Which color do you prefer?")
|
||||
assert not asks_contact("What's your budget range for this one?")
|
||||
assert not asks_contact("Can you send me more details about the Tang?") # 泛请求无渠道词
|
||||
|
||||
@@ -342,3 +342,25 @@ def test_number_first_whatsapp_whitespace_variants():
|
||||
# 两个接线位(scan + latest)都要走空白归一,任一崩都算回归
|
||||
assert latest_stated_contacts(m("0712345678 is my whats app")) == {
|
||||
"whatsapp": "0712345678"}
|
||||
|
||||
|
||||
# ---- 阿语/波斯语数字归一化(中东买家): 存库与比对全链 ASCII ----
|
||||
|
||||
|
||||
def test_arabic_digits_normalized():
|
||||
# 阿语数字(中东买家)提取后应转 ASCII,CRM 可直接拨
|
||||
confirmed, _ = split_validate({"whatsapp": "+٩٦٦٥٠١٢٣٤٥٦٧"})
|
||||
assert confirmed["whatsapp"] == "+966501234567"
|
||||
|
||||
|
||||
def test_arabic_digits_scan_latest_translated():
|
||||
# 捕获源头即转 ASCII: 用户消息里的阿语号码,scan/latest 的落库形态
|
||||
# 直接可拨;canon 比对也与 ASCII 形态同口径(不触发假性"改号"更正邮件)
|
||||
msgs = [{"role": "user", "content": "whatsapp: ٩٦٦٥٠١٢٣٤٥٦٧"}]
|
||||
assert scan_user_messages(msgs) == {"whatsapp": "966501234567"}
|
||||
assert latest_stated_contacts(msgs) == {"whatsapp": "966501234567"}
|
||||
|
||||
|
||||
def test_arabic_digits_canon_equals_ascii_form():
|
||||
from app.services.contact_pipeline import canon
|
||||
assert canon("+٩٦٦ ٥٠١ ٢٣٤ ٥٦٧") == canon("+966 501 234 567")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Red-line: `context` injection must be CONDITIONAL + WHITELIST only.
|
||||
|
||||
- No `context` passed -> `raw_info` stays `{}` (widget WS path unchanged).
|
||||
- `context` passed -> only `vehicle_name`/`vehicle_id` map to `app_*`.
|
||||
- `context` passed -> only `product_name`/`product_id` map to `app_*`.
|
||||
"""
|
||||
from sqlalchemy import select
|
||||
|
||||
@@ -33,13 +33,13 @@ async def test_context_seeds_whitelist_only(async_db):
|
||||
mgr = ConversationManager(db)
|
||||
conv = await mgr.create_conversation(
|
||||
context={
|
||||
"vehicle_name": "Tesla Model Y",
|
||||
"vehicle_id": "v123",
|
||||
"product_name": "HDPE PE100 Pipe DN110",
|
||||
"product_id": "p123",
|
||||
"evil_key": "should_be_ignored",
|
||||
}
|
||||
)
|
||||
raw = await _raw_info_for(async_db, conv.id)
|
||||
assert raw == {
|
||||
"app_vehicle_name": "Tesla Model Y",
|
||||
"app_vehicle_id": "v123",
|
||||
"app_product_name": "HDPE PE100 Pipe DN110",
|
||||
"app_product_id": "p123",
|
||||
}
|
||||
|
||||
@@ -482,17 +482,17 @@ def test_reminder_boundary_covers_delivery_and_arrangement():
|
||||
assert "职能边界" in ConversationManager._build_context_reminder(
|
||||
{}, "how long does shipping take?", [])
|
||||
assert "职能边界" in ConversationManager._build_context_reminder(
|
||||
{}, "可以约试驾吗", [])
|
||||
{}, "可以安排验厂吗", [])
|
||||
assert "职能边界" in ConversationManager._build_context_reminder(
|
||||
{}, "my budget is 20000, any recommendation?", [])
|
||||
|
||||
|
||||
def test_reminder_no_boundary_on_normal_car_questions():
|
||||
# 续航/配置/库存类正常问题不得误触发
|
||||
# 规格/配置/库存类正常问题不得误触发
|
||||
assert "职能边界" not in ConversationManager._build_context_reminder(
|
||||
{}, "what is the range of the Tang?", [])
|
||||
{}, "what is the pressure rating of the PE100 pipe?", [])
|
||||
assert "职能边界" not in ConversationManager._build_context_reminder(
|
||||
{}, "这款车续航多久", [])
|
||||
{}, "这根管耐压多少", [])
|
||||
|
||||
|
||||
def test_reminder_boundary_on_pressure_phrases():
|
||||
|
||||
Reference in New Issue
Block a user