feat: use assigned_to transfer command when dispatch assign succeeds

This commit is contained in:
2026-02-28 23:30:30 +08:00
parent ca7e195d8f
commit 5b8ca6fb02

View File

@@ -1307,11 +1307,45 @@ class QingjianAPIClient:
image_data['msg_type'] = 0 # 转为文本消息,让 agent_reply 处理
self._fire_and_forget(self._agent_reply_serialized(image_data))
async def _dispatch_assign_once(self) -> Dict[str, Any]:
"""
调用新的一键派单接口:
GET {DISPATCH_BASE_URL}/assign
Header: X-API-Key
"""
base_url = os.getenv("DISPATCH_BASE_URL", "http://1.12.50.92:8006").strip().rstrip("/")
api_key = os.getenv("DISPATCH_API_KEY", "tuhui_dispatch_key_2026").strip()
timeout_s = float(os.getenv("DISPATCH_TIMEOUT_SECONDS", "5"))
if not base_url or not api_key:
return {"success": False, "reason": "dispatch config missing"}
try:
import httpx
async with httpx.AsyncClient(timeout=timeout_s) as client:
resp = await client.get(
f"{base_url}/assign",
headers={"X-API-Key": api_key},
)
if resp.status_code != 200:
return {"success": False, "reason": f"http {resp.status_code}"}
data = resp.json() if resp.content else {}
ok = bool((data or {}).get("success", False))
return {
"success": ok,
"task_id": str((data or {}).get("task_id", "") or ""),
"assigned_to": str((data or {}).get("assigned_to", "") or ""),
"online_count": int((data or {}).get("online_count", 0) or 0),
"notification_sent": bool((data or {}).get("notification_sent", False)),
"raw": data,
}
except Exception as e:
return {"success": False, "reason": str(e)}
async def transfer_to_human(self, data: dict, transfer_msg: str = ""):
"""
转接人工客服。
1. 优先从 designer_roster 轮询派单(在线设计师)
2. 无人在线或未配置时,回退到 config/transfer_groups.json
1. 优先调用 dispatch 服务 GET /assign 一键派单
2. 派单失败时,回退旧版 designer_roster 派单
3. 无人在线或未配置时,回退到 config/transfer_groups.json
设计师在线状态:仅在转人工时按需查询,不轮询。
"""
if not self.websocket:
@@ -1320,8 +1354,25 @@ class QingjianAPIClient:
acc_id = data.get("acc_id", "")
group_id = None
assigned_to = ""
dispatch_res = await self._dispatch_assign_once()
if dispatch_res.get("success"):
assigned_to = str(dispatch_res.get("assigned_to", "") or "").strip()
logger.info(
f"一键派单成功 | task_id={dispatch_res.get('task_id','')} | assigned_to={assigned_to or '未知'} | online_count={dispatch_res.get('online_count',0)}"
)
metrics_emit(
"dispatch_assign_success",
acc_id=acc_id,
assigned_to=assigned_to,
online_count=dispatch_res.get("online_count", 0),
)
else:
logger.warning(f"一键派单失败,回退旧派单逻辑: {dispatch_res.get('reason', 'unknown')}")
metrics_emit("dispatch_assign_failed", acc_id=acc_id)
# 1. 转人工时按需查询设计师在线状态(调用另一台 AI 的查询服务),再派单
# 2. 派单失败时,回退旧版 designer_roster
if not dispatch_res.get("success"):
try:
from utils.designer_roster import poll_and_update_roster
from db.designer_roster_db import get_transfer_group_for_shop
@@ -1330,8 +1381,9 @@ class QingjianAPIClient:
except Exception as e:
logger.debug(f"设计师派单未启用或异常: {e}")
# 2. 无人在线时企微提醒
if not group_id:
# 3. 无人在线时企微提醒(新旧两套都没拿到在线结果时)
online_count = int(dispatch_res.get("online_count", 0) or 0)
if online_count <= 0 and not group_id:
try:
from config.config import WECHAT_WEBHOOK
if WECHAT_WEBHOOK:
@@ -1348,13 +1400,15 @@ class QingjianAPIClient:
except Exception as e:
logger.warning(f"企微提醒发送异常: {e}")
# 3. 回退到静态配置
# 4. 构造转接命令:有 assigned_to 用人名,否则回退分组
if assigned_to:
cmd = f"正在为你转接人工|[转移会话],{assigned_to},无原因"
await self.send_reply(data, cmd)
print(f"[{self.get_time()}] 已发送转接请求 (店铺:{acc_id or '未知'} -> 设计师:{assigned_to})")
return
if not group_id:
group_id = _get_transfer_group(acc_id)
# 先发一条提示语给客户
await self.send_reply(data, "亲,正在为您转接人工客服,请稍等~")
cmd = f"话术|[转移会话],分组{group_id},无原因"
await self.send_reply(data, cmd)
print(f"[{self.get_time()}] 已发送转接请求 (店铺:{acc_id or '未知'} -> 分组:{group_id})")