124 lines
5.9 KiB
Python
124 lines
5.9 KiB
Python
import json
|
||
import logging
|
||
|
||
logger = logging.getLogger("cs_agent")
|
||
|
||
|
||
async def handle_incoming_message(client, message: str, *, shop_type_resolver):
|
||
"""处理单条入站消息(从 websocket_client.py 拆出)。"""
|
||
timestamp = client.get_time()
|
||
try:
|
||
data = json.loads(message)
|
||
|
||
# 多进程分片检查:确保同一客户只由一个 worker 处理
|
||
customer_key = client._customer_key(data)
|
||
if not client._is_owned_by_this_worker(customer_key):
|
||
return
|
||
|
||
timestamp = client.get_time()
|
||
|
||
# 保存最后一条消息用于回复
|
||
client.last_msg = data
|
||
|
||
# 打印格式化的消息
|
||
logger.info(f"\n{'='*50}")
|
||
logger.info(f"[{timestamp}] 收到新消息:")
|
||
logger.info(f"{'='*50}")
|
||
logger.info(f" 消息ID: {data.get('msg_id', 'N/A')}")
|
||
logger.info(f" 账号ID: {client.to_chinese(data.get('acc_id', 'N/A'))}")
|
||
logger.info(f" 发送者ID: {client.to_chinese(data.get('from_id', 'N/A'))}")
|
||
logger.info(f" 发送者名称: {client.to_chinese(data.get('from_name', 'N/A'))}")
|
||
logger.info(f" 会话ID: {client.to_chinese(data.get('cy_id', 'N/A'))}")
|
||
logger.info(f" 平台类型: {data.get('acc_type', 'N/A')}")
|
||
logger.info(f" 消息类型: {client.get_msg_type_name(data.get('msg_type', 0))}")
|
||
logger.info(f" 消息内容: {client.to_chinese(data.get('msg', 'N/A'))}")
|
||
|
||
# 显示商品信息(如果有)
|
||
if data.get('goods_name'):
|
||
logger.info(f" 商品名称: {client.to_chinese(data.get('goods_name', ''))}")
|
||
if data.get('goods_order'):
|
||
logger.info(f" 订单信息: {client.to_chinese(data.get('goods_order', ''))}")
|
||
|
||
logger.info(f"{'='*50}\n")
|
||
|
||
# 消息去重:同一条消息不重复处理
|
||
msg_id = data.get('msg_id', '')
|
||
if msg_id and msg_id in client._replied_msg_ids:
|
||
logger.info(f"重复消息,跳过: {msg_id}")
|
||
return
|
||
if msg_id:
|
||
client._replied_msg_ids.append(msg_id) # deque 自动淘汰最旧的
|
||
|
||
# 空消息/无效消息过滤(N/A 或关键字段全为空)
|
||
from_id = data.get('from_id', '')
|
||
acc_id = data.get('acc_id', '')
|
||
if not from_id or from_id == 'N/A' or not acc_id or acc_id == 'N/A':
|
||
logger.info(f"[{client.get_time()}] 空消息跳过(from_id={from_id!r} acc_id={acc_id!r})")
|
||
return
|
||
client._log_inbound_once(data)
|
||
client._fire_and_forget(client._post_tianwang_callback("message_received", data))
|
||
|
||
# Gemini 店铺:不回复,直接跳过
|
||
goods_name = client.to_chinese(data.get('goods_name', '') or '')
|
||
if shop_type_resolver(acc_id, goods_name) == "gemini_api":
|
||
logger.info(f"[{client.get_time()}] Gemini 店铺消息,跳过")
|
||
client._push_chat_to_wechat_safe(
|
||
data=data,
|
||
customer_msg=data.get('msg', ''),
|
||
reply_msg="",
|
||
goods_name=goods_name,
|
||
tag="gemini店铺跳过",
|
||
)
|
||
return
|
||
|
||
# 使用 Agent 自动回复(仅处理文本消息)
|
||
if client.enable_agent:
|
||
msg_type = data.get('msg_type', 0)
|
||
if msg_type == 0:
|
||
if client._is_transfer_msg(data):
|
||
# 会话转交 → 主动打招呼
|
||
logger.info(f"[{client.get_time()}] 收到转交消息,发送问候")
|
||
greeting = client._pick_transfer_greeting()
|
||
await client.send_reply(data, greeting)
|
||
client._push_chat_to_wechat_safe(
|
||
data=data,
|
||
customer_msg=data.get('msg', ''),
|
||
reply_msg=greeting,
|
||
tag="转交问候",
|
||
)
|
||
elif client._is_shop_card(data):
|
||
# 进店卡片:有历史对话就不回复,没有才打招呼(Gemini 已在上面统一跳过)
|
||
cid = data.get('from_id', '')
|
||
acc_id = data.get('acc_id', '')
|
||
residual_text = client._extract_customer_text_from_shop_card_msg(data.get('msg', ''))
|
||
if residual_text:
|
||
logger.info(f"[{client.get_time()}] 进店卡片携带客户文本,转普通消息处理: {residual_text}")
|
||
patched = dict(data)
|
||
patched['msg'] = residual_text
|
||
await client._debounce_agent_reply(patched)
|
||
elif client._has_chat_history(cid, acc_id=acc_id):
|
||
logger.info(f"[{client.get_time()}] 进店卡片(已有记录),跳过")
|
||
else:
|
||
logger.info(f"[{client.get_time()}] 进店卡片(新客户),发送问候")
|
||
greeting = "在呢,发图来我看看"
|
||
await client.send_reply(data, greeting)
|
||
client._push_chat_to_wechat_safe(
|
||
data=data,
|
||
customer_msg=data.get('msg', ''),
|
||
reply_msg=greeting,
|
||
goods_name=goods_name,
|
||
tag="进店卡片问候",
|
||
)
|
||
elif await client._handle_system_inquiry(data):
|
||
logger.info(f"[{client.get_time()}] 系统客服询单消息,已按规则处理")
|
||
elif client._should_ignore(data):
|
||
logger.info(f"[{client.get_time()}] 系统通知,跳过回复")
|
||
else:
|
||
await client._debounce_agent_reply(data)
|
||
elif msg_type == 1:
|
||
# 图片消息直接处理,不走防抖(图片不会连续多发)
|
||
await client.handle_image_message(data)
|
||
|
||
except json.JSONDecodeError:
|
||
logger.info(f"[{timestamp}] 收到非JSON消息: {message}")
|