refactor: migrate workflow to v2 core and archive legacy modules
This commit is contained in:
143
legacy/websocket_system_inquiry_flow.py
Normal file
143
legacy/websocket_system_inquiry_flow.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from utils.metrics_tracker import emit as metrics_emit
|
||||
|
||||
logger = logging.getLogger("cs_agent")
|
||||
|
||||
|
||||
def load_system_inquiry_rules() -> Dict[str, Any]:
|
||||
"""加载系统客服询单规则(全局 + 店铺覆盖)。"""
|
||||
from config.config import (
|
||||
SYSTEM_INQUIRY_ENABLED,
|
||||
SYSTEM_INQUIRY_DEFAULT_ACTION,
|
||||
SYSTEM_INQUIRY_DEFAULT_REPLY,
|
||||
SYSTEM_INQUIRY_RULES_FILE,
|
||||
)
|
||||
|
||||
enabled_env = os.getenv("SYSTEM_INQUIRY_ENABLED")
|
||||
enabled = (
|
||||
enabled_env.lower() in ("1", "true", "yes")
|
||||
if isinstance(enabled_env, str)
|
||||
else bool(SYSTEM_INQUIRY_ENABLED)
|
||||
)
|
||||
action = (os.getenv("SYSTEM_INQUIRY_DEFAULT_ACTION") or SYSTEM_INQUIRY_DEFAULT_ACTION or "silent").strip().lower()
|
||||
reply = os.getenv("SYSTEM_INQUIRY_DEFAULT_REPLY") or SYSTEM_INQUIRY_DEFAULT_REPLY or ""
|
||||
rules_file = os.getenv("SYSTEM_INQUIRY_RULES_FILE") or str(SYSTEM_INQUIRY_RULES_FILE)
|
||||
defaults: Dict[str, Any] = {
|
||||
"enabled": bool(enabled),
|
||||
"default_action": action,
|
||||
"default_reply": reply,
|
||||
"sender_keywords": ["系统客服", "官方客服", "平台客服", "机器人客服", "商家客服系统"],
|
||||
"message_keywords": ["系统询单", "代客咨询", "平台代问", "系统代发", "客服询单"],
|
||||
"shops": {},
|
||||
}
|
||||
try:
|
||||
p = Path(rules_file)
|
||||
if p.exists():
|
||||
with p.open("r", encoding="utf-8") as f:
|
||||
loaded = json.load(f)
|
||||
if isinstance(loaded, dict):
|
||||
defaults.update(loaded)
|
||||
except Exception as e:
|
||||
logger.warning("系统询单规则加载失败,使用默认规则: %s", e)
|
||||
return defaults
|
||||
|
||||
|
||||
def normalize_kw_list(v: Any) -> List[str]:
|
||||
if not isinstance(v, list):
|
||||
return []
|
||||
return [str(x).strip().lower() for x in v if str(x).strip()]
|
||||
|
||||
|
||||
def resolve_system_inquiry_policy(client, acc_id: str) -> Dict[str, Any]:
|
||||
"""根据店铺合并系统询单策略。"""
|
||||
from config.config import SYSTEM_INQUIRY_SHOPS
|
||||
|
||||
rules = client._system_inquiry_rules or {}
|
||||
if not bool(rules.get("enabled", True)):
|
||||
return {"enabled": False}
|
||||
|
||||
shops_env = os.getenv("SYSTEM_INQUIRY_SHOPS", SYSTEM_INQUIRY_SHOPS or "")
|
||||
shop_whitelist = [s.strip() for s in shops_env.split(",") if s.strip()]
|
||||
if shop_whitelist and (acc_id or "") not in shop_whitelist:
|
||||
return {"enabled": False}
|
||||
|
||||
policy: Dict[str, Any] = {
|
||||
"enabled": True,
|
||||
"action": str(rules.get("default_action", "silent")).strip().lower(),
|
||||
"reply": str(rules.get("default_reply", "")).strip(),
|
||||
"sender_keywords": normalize_kw_list(rules.get("sender_keywords")),
|
||||
"message_keywords": normalize_kw_list(rules.get("message_keywords")),
|
||||
}
|
||||
shop_cfg = (rules.get("shops") or {}).get(acc_id or "", {})
|
||||
if isinstance(shop_cfg, dict):
|
||||
if "enabled" in shop_cfg and not bool(shop_cfg.get("enabled", True)):
|
||||
return {"enabled": False}
|
||||
if shop_cfg.get("action"):
|
||||
policy["action"] = str(shop_cfg.get("action")).strip().lower()
|
||||
if shop_cfg.get("reply"):
|
||||
policy["reply"] = str(shop_cfg.get("reply")).strip()
|
||||
if isinstance(shop_cfg.get("sender_keywords"), list):
|
||||
policy["sender_keywords"] = normalize_kw_list(shop_cfg.get("sender_keywords"))
|
||||
if isinstance(shop_cfg.get("message_keywords"), list):
|
||||
policy["message_keywords"] = normalize_kw_list(shop_cfg.get("message_keywords"))
|
||||
if policy["action"] not in ("silent", "reply", "transfer"):
|
||||
policy["action"] = "silent"
|
||||
return policy
|
||||
|
||||
|
||||
def match_system_inquiry(client, data: dict, policy: Dict[str, Any]) -> bool:
|
||||
"""识别是否为系统客服询单消息。"""
|
||||
if not policy.get("enabled", False):
|
||||
return False
|
||||
|
||||
from_name = client.to_chinese(data.get("from_name", "") or "").lower()
|
||||
from_id = str(data.get("from_id", "") or "").lower()
|
||||
msg = client.to_chinese(data.get("msg", "") or "").lower()
|
||||
|
||||
sender_hits = 0
|
||||
for kw in policy.get("sender_keywords", []):
|
||||
if kw and (kw in from_name or kw in from_id):
|
||||
sender_hits += 1
|
||||
message_hits = 0
|
||||
for kw in policy.get("message_keywords", []):
|
||||
if kw and kw in msg:
|
||||
message_hits += 1
|
||||
|
||||
# 优先看发送者特征;纯文本命中时至少要求两个关键词,降低误判风险
|
||||
return sender_hits > 0 or message_hits >= 2
|
||||
|
||||
|
||||
async def handle_system_inquiry(client, data: dict) -> bool:
|
||||
"""命中系统询单后按策略处理。"""
|
||||
acc_id = data.get("acc_id", "")
|
||||
policy = resolve_system_inquiry_policy(client, acc_id)
|
||||
if not match_system_inquiry(client, data, policy):
|
||||
return False
|
||||
|
||||
customer_id = data.get("from_id", "")
|
||||
metrics_emit("system_inquiry_detected", customer_id=customer_id, acc_id=acc_id)
|
||||
action = policy.get("action", "silent")
|
||||
logger.info("系统询单命中 | 店铺:%s | 客户:%s | action:%s", acc_id, customer_id, action)
|
||||
|
||||
if action == "reply":
|
||||
reply = await client._compose_ai_scene_reply(
|
||||
original_msg=data,
|
||||
scene="system_inquiry_reply",
|
||||
intent_hint="这是系统客服询单消息,简短确认已收到并说明会跟进即可。",
|
||||
fallback=(policy.get("reply") or "您好,这边已收到询单消息,稍后由人工客服跟进处理。"),
|
||||
)
|
||||
await client.send_reply(data, reply)
|
||||
metrics_emit("system_inquiry_auto_reply", customer_id=customer_id, acc_id=acc_id)
|
||||
return True
|
||||
if action == "transfer":
|
||||
await client.transfer_to_human(data, "系统询单转人工")
|
||||
metrics_emit("system_inquiry_transfer", customer_id=customer_id, acc_id=acc_id)
|
||||
return True
|
||||
|
||||
metrics_emit("system_inquiry_ignored", customer_id=customer_id, acc_id=acc_id)
|
||||
return True
|
||||
Reference in New Issue
Block a user