"""AI获客 - 客户咨询接口""" from fastapi import APIRouter, HTTPException from pydantic import BaseModel import json, os, datetime, urllib.request router = APIRouter(prefix="/api/cma/lead", tags=["AI获客"]) # 客户咨询通知唯一通道:系统总线中继 8660 → 任总 DM。 # 2026-10-22 起取代旧的 ai-cs routing-live.py(该 profile/user 已下线,runuser 必然失败且异常被吞, # 导致线索静默丢失通知)。中继类别按契约取 fallback(无会话兜底),company 类被中继直接拒绝。 BUS_RELAY_URL = "http://127.0.0.1:8660/bus/send" BUS_KEY_FILE = "/srv/hermes/shared/.secrets/bus_relay.key" BOSS_USERID = "200653946" # 任富海 NOTIFY_LOG = "/root/leads/notify.log" class LeadRequest(BaseModel): name: str phone: str requirement: str = "" source: str = "sxbh.ltd" def _log_notify(ok, detail): """通知结果落痕(旧实现 except: pass 静默吞异常,导致线索漏通知无人知晓)""" try: os.makedirs(os.path.dirname(NOTIFY_LOG), exist_ok=True) with open(NOTIFY_LOG, "a", encoding="utf-8") as f: f.write("%s %s %s\n" % (datetime.datetime.now().isoformat(timespec="seconds"), "OK" if ok else "FAIL", detail)) except Exception: pass def notify_boss(name, phone, requirement): """客户咨询通知:经系统总线中继 8660 推任总 DM。失败不阻断主流程,但必须留痕。""" now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") content = ( "## 新客户咨询(sxbh.ltd 官网)\n" f"> 姓名:{name}\n" f"> 电话:{phone}\n" f"> 需求:{requirement or '(未填)'}\n" f"> 时间:{now}\n\n" "承诺 30 分钟内联系。" ) try: with open(BUS_KEY_FILE, encoding="utf-8") as f: key = f.read().strip() if not key: raise RuntimeError("bus key empty") payload = json.dumps({ "touser": BOSS_USERID, "msgtype": "markdown", "content": content, "notice_class": "fallback", }, ensure_ascii=False).encode("utf-8") req = urllib.request.Request( BUS_RELAY_URL, data=payload, headers={"Content-Type": "application/json", "X-API-Key": key, "X-Notice-Class": "fallback"}, method="POST", ) with urllib.request.urlopen(req, timeout=10) as resp: body = resp.read().decode("utf-8", "ignore")[:300] _log_notify(True, body) return True except Exception as e: _log_notify(False, "%s: %s" % (type(e).__name__, e)) return False @router.post("") def create_lead(data: LeadRequest): """接收客户咨询并保存""" record = data.model_dump() record["timestamp"] = datetime.datetime.now().isoformat() record["status"] = "new" log_dir = "/root/leads" os.makedirs(log_dir, exist_ok=True) with open(f"{log_dir}/leads.json", "a") as f: f.write(json.dumps(record, ensure_ascii=False) + "\n") # 客户咨询通知唯一通道:推任总 DM(经 ai-cs 分流);不再推 8800 全员群 # (2026-10-22 裁定:8800 仅限内容类群发,客户线索含个人信息,不得进全员群) notify_boss(data.name, data.phone, data.requirement) return {"success": True, "message": "咨询已提交,我们将在30分钟内联系您"}