fix: 个人微信发送对齐iLink规范(base_info/client_id/ret检查); 会话过期检测+重扫UI; 仅发送成功才写历史
This commit is contained in:
1 parent
62f3986e04
commit
2eeaf1d293
2 files changed
+88
-31
No files matched your search
@@ -164,16 +164,23 @@ def _wechat_get_updates(baseurl: str, bot_token: str, cursor: str):
|
||||
return [], cursor
|
||||
|
||||
|
||||
def _wechat_send_message(baseurl: str, bot_token: str, to_user_id: str, context_token: str, text: str) -> bool:
|
||||
"""发送文本回复(必须带 context_token 关联到正确的对话窗口)。失败重试一次。"""
|
||||
payload = {"msg": {
|
||||
"to_user_id": to_user_id,
|
||||
"message_type": 2,
|
||||
"message_state": 2,
|
||||
"context_token": context_token,
|
||||
"item_list": [{"type": 1, "text_item": {"text": text}}],
|
||||
}}
|
||||
last = False
|
||||
def _wechat_send_message(baseurl: str, bot_token: str, to_user_id: str, context_token: str, text: str):
|
||||
"""发送文本回复(必须带 context_token 关联到正确的对话窗口)。
|
||||
返回 (ok, ret, body)。ret=-14=会话过期需重扫;ret=-2=token 失效。"""
|
||||
import uuid as _uuid
|
||||
payload = {
|
||||
"msg": {
|
||||
"from_user_id": "",
|
||||
"to_user_id": to_user_id,
|
||||
"client_id": "py-" + str(_uuid.uuid4()),
|
||||
"message_type": 2,
|
||||
"message_state": 2,
|
||||
"context_token": context_token,
|
||||
"item_list": [{"type": 1, "text_item": {"text": text}}],
|
||||
},
|
||||
"base_info": {"channel_version": "1.0.2"},
|
||||
}
|
||||
last_body = {}
|
||||
for _ in range(2):
|
||||
try:
|
||||
resp = requests.post(
|
||||
@@ -182,12 +189,25 @@ def _wechat_send_message(baseurl: str, bot_token: str, to_user_id: str, context_
|
||||
json=payload,
|
||||
timeout=20,
|
||||
)
|
||||
last = resp.ok
|
||||
if last:
|
||||
return True
|
||||
try:
|
||||
body = resp.json() if resp.content else {}
|
||||
except Exception:
|
||||
body = {}
|
||||
last_body = body
|
||||
ret = body.get("ret") if isinstance(body, dict) else None
|
||||
try:
|
||||
with open("/tmp/wechat_send.log", "a", encoding="utf-8") as _f:
|
||||
_f.write(datetime.now().isoformat() + " SEND_HTTP=%s ret=%s body=%s\n"
|
||||
% (resp.status_code, ret, json.dumps(body, ensure_ascii=False)[:300]))
|
||||
except Exception:
|
||||
pass
|
||||
if resp.ok and (ret is None or ret == 0 or not body):
|
||||
return True, ret, body
|
||||
if ret in (-2, -14):
|
||||
return False, ret, body # 鉴权/会话失效,立即停止重试
|
||||
except Exception:
|
||||
last = False
|
||||
return last
|
||||
pass
|
||||
return False, (last_body.get("ret") if isinstance(last_body, dict) else None), last_body
|
||||
|
||||
|
||||
def _wechat_extract_text(msg: dict) -> str:
|
||||
@@ -247,6 +267,22 @@ def _log_chat(user_id, platform, from_user, context_token, role, content):
|
||||
# ============================================================
|
||||
# 后台接收线程(每用户独立)
|
||||
# ============================================================
|
||||
def _mark_wechat_expired(account_id: int):
|
||||
"""发送会话失效(ret=-14/-2):标记账号需重扫,并清除失效 token。"""
|
||||
db = None
|
||||
try:
|
||||
db = SessionLocal()
|
||||
_execute_raw(db, text(
|
||||
"UPDATE im_bot_wechat_account SET status='expired', bot_token=NULL, "
|
||||
"updated_at=:ts WHERE id=:aid"
|
||||
), {"aid": account_id, "ts": datetime.now()})
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
if db:
|
||||
db.close()
|
||||
|
||||
|
||||
def _wechat_receiver_loop(account_id: int):
|
||||
"""长轮询个人微信消息 → 七虎AI 回复 → 发送。"""
|
||||
cursor = ""
|
||||
@@ -284,17 +320,23 @@ def _wechat_receiver_loop(account_id: int):
|
||||
pass
|
||||
# 先生成回复(此时历史尚未包含本条,避免重复)
|
||||
reply = _qihua_reply(content, owner_uid)
|
||||
ok = _wechat_send_message(baseurl, bot_token, sender, ctx, reply)
|
||||
# 持久化对话历史
|
||||
if owner_uid:
|
||||
_log_chat(owner_uid, "personal_wechat", sender, ctx, "user", content)
|
||||
_log_chat(owner_uid, "personal_wechat", sender, ctx, "assistant", reply)
|
||||
try:
|
||||
with open("/tmp/wechat_send.log", "a", encoding="utf-8") as _f:
|
||||
_f.write(datetime.now().isoformat() + " ok=" + str(ok)
|
||||
+ " sender=" + repr(sender) + " ctx=" + repr(ctx) + "\n")
|
||||
except Exception:
|
||||
pass
|
||||
ok, ret, _ = _wechat_send_message(baseurl, bot_token, sender, ctx, reply)
|
||||
if ok:
|
||||
# 仅发送成功才写对话历史(避免“发了但没收到”的误导记录)
|
||||
if owner_uid:
|
||||
_log_chat(owner_uid, "personal_wechat", sender, ctx, "user", content)
|
||||
_log_chat(owner_uid, "personal_wechat", sender, ctx, "assistant", reply)
|
||||
else:
|
||||
try:
|
||||
with open("/tmp/wechat_send.log", "a", encoding="utf-8") as _f:
|
||||
_f.write(datetime.now().isoformat() + " SEND_FAIL ret=%s sender=%s\n"
|
||||
% (ret, repr(sender)))
|
||||
except Exception:
|
||||
pass
|
||||
if ret in (-2, -14):
|
||||
# 会话/鉴权失效:标记需重扫并停止接收线程
|
||||
_mark_wechat_expired(d["id"])
|
||||
return
|
||||
time.sleep(1)
|
||||
except Exception:
|
||||
time.sleep(5)
|
||||
@@ -324,6 +366,7 @@ async def wechat_status(user: User = Depends(get_current_user)):
|
||||
d = _row_to_dict(row)
|
||||
return {"success": True, "data": {
|
||||
"connected": d.get("status") == "connected",
|
||||
"status": d.get("status"),
|
||||
"configured": True,
|
||||
"baseurl": d.get("baseurl"),
|
||||
"ilink_bot_id": d.get("ilink_bot_id"),
|
||||
|
||||
Reference in new issue
Block a user