From 5b8ca6fb023a0e639fc394ae5b4037a859937b43 Mon Sep 17 00:00:00 2001 From: jimi <1847930177@qq.com> Date: Sat, 28 Feb 2026 23:30:30 +0800 Subject: [PATCH] feat: use assigned_to transfer command when dispatch assign succeeds --- core/websocket_client.py | 88 ++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/core/websocket_client.py b/core/websocket_client.py index 8d36005..5ca9094 100755 --- a/core/websocket_client.py +++ b/core/websocket_client.py @@ -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,18 +1354,36 @@ 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 的查询服务),再派单 - try: - from utils.designer_roster import poll_and_update_roster - from db.designer_roster_db import get_transfer_group_for_shop - await poll_and_update_roster() - group_id = get_transfer_group_for_shop(acc_id) - except Exception as e: - logger.debug(f"设计师派单未启用或异常: {e}") + # 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 + await poll_and_update_roster() + group_id = get_transfer_group_for_shop(acc_id) + 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})")