feat: use assigned_to transfer command when dispatch assign succeeds
This commit is contained in:
@@ -1307,11 +1307,45 @@ class QingjianAPIClient:
|
|||||||
image_data['msg_type'] = 0 # 转为文本消息,让 agent_reply 处理
|
image_data['msg_type'] = 0 # 转为文本消息,让 agent_reply 处理
|
||||||
self._fire_and_forget(self._agent_reply_serialized(image_data))
|
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 = ""):
|
async def transfer_to_human(self, data: dict, transfer_msg: str = ""):
|
||||||
"""
|
"""
|
||||||
转接人工客服。
|
转接人工客服。
|
||||||
1. 优先从 designer_roster 轮询派单(在线设计师)
|
1. 优先调用 dispatch 服务 GET /assign 一键派单
|
||||||
2. 无人在线或未配置时,回退到 config/transfer_groups.json
|
2. 派单失败时,回退旧版 designer_roster 派单
|
||||||
|
3. 无人在线或未配置时,回退到 config/transfer_groups.json
|
||||||
设计师在线状态:仅在转人工时按需查询,不轮询。
|
设计师在线状态:仅在转人工时按需查询,不轮询。
|
||||||
"""
|
"""
|
||||||
if not self.websocket:
|
if not self.websocket:
|
||||||
@@ -1320,18 +1354,36 @@ class QingjianAPIClient:
|
|||||||
|
|
||||||
acc_id = data.get("acc_id", "")
|
acc_id = data.get("acc_id", "")
|
||||||
group_id = None
|
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
|
||||||
try:
|
if not dispatch_res.get("success"):
|
||||||
from utils.designer_roster import poll_and_update_roster
|
try:
|
||||||
from db.designer_roster_db import get_transfer_group_for_shop
|
from utils.designer_roster import poll_and_update_roster
|
||||||
await poll_and_update_roster()
|
from db.designer_roster_db import get_transfer_group_for_shop
|
||||||
group_id = get_transfer_group_for_shop(acc_id)
|
await poll_and_update_roster()
|
||||||
except Exception as e:
|
group_id = get_transfer_group_for_shop(acc_id)
|
||||||
logger.debug(f"设计师派单未启用或异常: {e}")
|
except Exception as e:
|
||||||
|
logger.debug(f"设计师派单未启用或异常: {e}")
|
||||||
|
|
||||||
# 2. 无人在线时企微提醒
|
# 3. 无人在线时企微提醒(新旧两套都没拿到在线结果时)
|
||||||
if not group_id:
|
online_count = int(dispatch_res.get("online_count", 0) or 0)
|
||||||
|
if online_count <= 0 and not group_id:
|
||||||
try:
|
try:
|
||||||
from config.config import WECHAT_WEBHOOK
|
from config.config import WECHAT_WEBHOOK
|
||||||
if WECHAT_WEBHOOK:
|
if WECHAT_WEBHOOK:
|
||||||
@@ -1348,13 +1400,15 @@ class QingjianAPIClient:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"企微提醒发送异常: {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:
|
if not group_id:
|
||||||
group_id = _get_transfer_group(acc_id)
|
group_id = _get_transfer_group(acc_id)
|
||||||
|
|
||||||
# 先发一条提示语给客户
|
|
||||||
await self.send_reply(data, "亲,正在为您转接人工客服,请稍等~")
|
|
||||||
|
|
||||||
cmd = f"话术|[转移会话],分组{group_id},无原因"
|
cmd = f"话术|[转移会话],分组{group_id},无原因"
|
||||||
await self.send_reply(data, cmd)
|
await self.send_reply(data, cmd)
|
||||||
print(f"[{self.get_time()}] 已发送转接请求 (店铺:{acc_id or '未知'} -> 分组:{group_id})")
|
print(f"[{self.get_time()}] 已发送转接请求 (店铺:{acc_id or '未知'} -> 分组:{group_id})")
|
||||||
|
|||||||
Reference in New Issue
Block a user