修复QQ读不出/读旧数据/auto-reply错发平台
问题1: QQ读不出消息 — daemon线程SetForegroundWindow频繁失败
-> _run_loop添加PeekMessage创建Windows消息队列
-> _attach_set_foreground内部异常全部捕获,不抛给调用者
问题2: QQ读旧剪贴板数据 — PostMessage键盘 Electron不响应
-> 移除前台跳过检查(降频已足够,20s一次不频繁)
-> _click_message_area PostMessage->SendMessage(Electron响应同步消息)
-> 移除_force_scroll_bottom(PostMessage对Electron无效)
问题3: WeChat消息错发给QQ — auto-reply daemon线程SetForegroundWindow失败
-> auto_reply.on_kb_match不再直接调用_paste_and_send
-> 改为get_reply_data返回{platform,answer,sender}给主线程
-> gui.py添加_reply_queue + _flush_reply_queue(主线程after轮询)
-> _execute_reply在主线程执行_search_contact和_paste_and_send
(SetForegroundWindow从主线程调用永远可靠)
This commit is contained in:
@@ -51,11 +51,16 @@ class MsgBotApp(ctk.CTk):
|
||||
|
||||
# 日志队列(线程安全)
|
||||
self._log_queue: queue.Queue[str] = queue.Queue()
|
||||
# 自动回复执行队列(转发到主线程,避免 daemon 线程 SetForegroundWindow 失败)
|
||||
self._reply_queue: queue.Queue[dict] = queue.Queue()
|
||||
self._build_ui()
|
||||
|
||||
# 定时从队列取日志刷新
|
||||
self.after(200, self._flush_log)
|
||||
|
||||
# 定时处理自动回复队列(主线程才能可靠 SetForegroundWindow)
|
||||
self.after(200, self._flush_reply_queue)
|
||||
|
||||
# 窗口关闭
|
||||
self.protocol("WM_DELETE_WINDOW", self._on_close)
|
||||
|
||||
@@ -303,7 +308,7 @@ class MsgBotApp(ctk.CTk):
|
||||
args=(platform, msg), daemon=True).start()
|
||||
|
||||
def _search_and_log(self, platform: str, msg: str):
|
||||
"""搜索知识库并输出结果,匹配成功时触发自动回复"""
|
||||
"""搜索知识库并输出结果,匹配成功时队列自动回复到主线程"""
|
||||
results = self.kb.search(msg, top_k=3)
|
||||
lines = [f"[{platform.upper()}] {msg}"]
|
||||
if results:
|
||||
@@ -318,8 +323,10 @@ class MsgBotApp(ctk.CTk):
|
||||
lines.append(f" 📄 [{title}] (匹配度 {score:.2f})")
|
||||
lines.append(f" {snippet}")
|
||||
|
||||
# 自动回复(最高分结果,阈值在 AutoReply 内部判断)
|
||||
self.ar.on_kb_match(platform, msg, results[0][0], results[0][1])
|
||||
# 自动回复:队列到主线程执行(daemon 线程不能可靠 SetForegroundWindow)
|
||||
reply_data = self.ar.get_reply_data(platform, msg, results[0][0], results[0][1])
|
||||
if reply_data:
|
||||
self._reply_queue.put(reply_data)
|
||||
else:
|
||||
lines.append(" ❌ 知识库中未找到相关答案")
|
||||
|
||||
@@ -343,6 +350,34 @@ class MsgBotApp(ctk.CTk):
|
||||
pass
|
||||
self.after(200, self._flush_log)
|
||||
|
||||
def _flush_reply_queue(self):
|
||||
"""从自动回复队列消费——主线程执行,SetForegroundWindow 可靠。"""
|
||||
try:
|
||||
while True:
|
||||
data = self._reply_queue.get_nowait()
|
||||
self._execute_reply(data)
|
||||
except queue.Empty:
|
||||
pass
|
||||
self.after(200, self._flush_reply_queue)
|
||||
|
||||
def _execute_reply(self, data: dict):
|
||||
"""主线程执行自动回复发送。"""
|
||||
platform = data["platform"]
|
||||
answer = data["answer"]
|
||||
sender = data.get("sender")
|
||||
|
||||
if sender:
|
||||
# 搜索联系人切换会话
|
||||
found = self.monitor._search_contact(platform, sender)
|
||||
if not found:
|
||||
self._log(f"[{platform}] ⚠ 找不到联系人 {sender},当前会话回复")
|
||||
# 发送(主线程 SetForegroundWindow 可靠)
|
||||
ok = self.monitor._paste_and_send(platform, answer)
|
||||
if ok:
|
||||
self._log(f"[{platform}] 🤖 已自动回复: {answer[:60]}...")
|
||||
else:
|
||||
self._log(f"[{platform}] ⚠ 自动回复发送失败")
|
||||
|
||||
def _clear_log(self):
|
||||
self._log_text.configure(state="normal")
|
||||
self._log_text.delete("1.0", "end")
|
||||
|
||||
Reference in New Issue
Block a user