修复短句碎片和模糊重复跳过的误报:允许包含括号的短消息,问句不视为模糊重复

This commit is contained in:
youpaishidifu
2026-08-12 11:45:50 +08:00
parent 7e3b3141b4
commit 1738daffec
4 changed files with 311 additions and 8 deletions
+96
View File
@@ -0,0 +1,96 @@
1:2026-08-08 21:24:25,201 [msgbot] INFO: 消息问答助手启动中...
10:2026-08-08 21:25:12,874 [msgbot.monitor] WARNING: [mem-watch] RSS=645MB threads=37 gdi=118 hash=0 seen=0 garbage={} easyocr_alive=False
11:2026-08-08 21:25:12,874 [msgbot.monitor] INFO: [mem-watch] 内存看门狗已启动(每30s记录 RSS/线程/GDI)
14:2026-08-08 21:25:12,877 [msgbot.monitor] INFO: 消息监控已启动
18:2026-08-08 21:25:16,225 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
26:2026-08-08 21:25:18,993 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程存活但握手未完成,等待就绪(≤60s)...
27:2026-08-08 21:25:24,892 [msgbot.monitor] WARNING: [wechat] _ensure_hwnd 超时(12s),跳过本轮
28:2026-08-08 21:25:28,993 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
47:2026-08-08 21:25:31,697 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程存活但握手未完成,等待就绪(≤60s)...
48:2026-08-08 21:25:31,757 [msgbot.monitor] INFO: [ocr] EasyOCR 子进程就绪
49:2026-08-08 21:25:31,760 [msgbot.monitor] DEBUG: [ocr] 已截断崩溃日志,清除旧条目
66:2026-08-08 21:25:40,183 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[0]: '哪儿能下到登录插件啊?'
67:2026-08-08 21:25:40,184 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[1]: '等级'
68:2026-08-08 21:25:40,184 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[2]: '评'
69:2026-08-08 21:25:40,184 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[3]: '151'
70:2026-08-08 21:25:40,185 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[4]: '成'
71:2026-08-08 21:25:40,185 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[5]: '52'
72:2026-08-08 21:25:40,185 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[6]: '玩家'
73:2026-08-08 21:25:40,185 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[7]: '53'
74:2026-08-08 21:25:40,185 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[8]: '成'
75:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[9]: '54'
76:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[10]: '成功'
77:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[11]: '玩家应尊重他人的合法权益;'
78:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[12]: '不得进行任何形式'
79:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[13]: '17:42:23'
80:2026-08-08 21:25:40,186 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[14]: 'PHP的用户端有哪两种登录模式?'
81:2026-08-08 21:25:40,187 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[15]: '20;22:50'
82:2026-08-08 21:25:40,187 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[16]: '应该去哪儿下载登录插件?'
83:2026-08-08 21:25:40,187 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[17]: '玩家应尊重他人的合法权益;'
84:2026-08-08 21:25:40,187 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[18]: '不得进行任何形式'
85:2026-08-08 21:25:40,187 [msgbot.monitor] INFO: [ocr] [easyocr/原始] line[19]: '['
86:2026-08-08 21:25:40,188 [msgbot.monitor] DEBUG: [ocr] 引擎对比: win=30.2(行1,字符231) vs easy=45.0(行20,字符135) → 选easyocr(分数差14.8, 胜率100%, 1轮)
107:2026-08-08 21:25:44,211 [msgbot.monitor] WARNING: [mem-watch] RSS=723MB threads=46 gdi=119 hash=2 seen=0 garbage={'qq': 0} easyocr_alive=True
108:2026-08-08 21:25:48,540 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
174:2026-08-08 21:25:52,422 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
189:2026-08-08 21:25:56,529 [msgbot.monitor] DEBUG: [ocr] EasyOCR 连续3次超时,杀子进程重来
190:2026-08-08 21:25:57,176 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(连续超时): terminate 后正常退出
191:2026-08-08 21:25:57,176 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(连续超时) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:25:47.528199,距现在9.0s) | 崩溃日志=2026-08-08 21:25:29.204440 [easyocr_worker] 启动 (pid=28888)
253:2026-08-08 21:25:59,490 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
271:2026-08-08 21:26:08,548 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程存活但握手未完成,等待就绪(≤60s)...
272:2026-08-08 21:26:09,474 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
295:2026-08-08 21:26:10,273 [msgbot.monitor] INFO: [ocr] EasyOCR 子进程就绪
296:2026-08-08 21:26:10,275 [msgbot.monitor] DEBUG: [ocr] 已截断崩溃日志,清除旧条目
303:2026-08-08 21:26:14,307 [msgbot.monitor] WARNING: [mem-watch] RSS=723MB threads=41 gdi=119 hash=2 seen=0 garbage={'qq': 0, 'wechat': 0} easyocr_alive=True
304:2026-08-08 21:26:18,574 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
352:2026-08-08 21:26:21,766 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
379:2026-08-08 21:26:26,781 [msgbot.monitor] DEBUG: [ocr] EasyOCR 锁竞争超时(15s),另一线程正在处理中,本次跳过(正常行为)
380:2026-08-08 21:26:26,905 [msgbot.monitor] DEBUG: [ocr] EasyOCR 连续3次超时,杀子进程重来
381:2026-08-08 21:26:27,541 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(连续超时): terminate 后正常退出
382:2026-08-08 21:26:27,541 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(连续超时) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:26:17.894109,距现在9.0s)
443:2026-08-08 21:26:29,920 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
459:2026-08-08 21:26:30,933 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程存活但握手未完成,等待就绪(≤60s)...
460:2026-08-08 21:26:39,939 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
481:2026-08-08 21:26:40,705 [msgbot.monitor] INFO: [ocr] EasyOCR 子进程就绪
482:2026-08-08 21:26:40,706 [msgbot.monitor] DEBUG: [ocr] 已截断崩溃日志,清除旧条目
483:2026-08-08 21:26:40,967 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
538:2026-08-08 21:26:44,328 [msgbot.monitor] WARNING: [mem-watch] RSS=711MB threads=37 gdi=119 hash=2 seen=0 garbage={'qq': 0, 'wechat': 0} easyocr_alive=True
546:2026-08-08 21:26:52,236 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
572:2026-08-08 21:26:54,711 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
613:2026-08-08 21:26:57,217 [msgbot.monitor] DEBUG: [ocr] EasyOCR 锁竞争超时(15s),另一线程正在处理中,本次跳过(正常行为)
615:2026-08-08 21:26:57,466 [msgbot.monitor] DEBUG: [ocr] EasyOCR 连续3次超时,杀子进程重来
623:2026-08-08 21:26:58,134 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(连续超时): terminate 后正常退出
624:2026-08-08 21:26:58,135 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(连续超时) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:26:48.430053,距现在9.0s) | 崩溃日志=2026-08-08 21:26:38.455250 [easyocr_worker] 启动 (pid=3968)
688:2026-08-08 21:27:00,523 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
705:2026-08-08 21:27:01,544 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程存活但握手未完成,等待就绪(≤60s)...
706:2026-08-08 21:27:10,528 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
727:2026-08-08 21:27:11,245 [msgbot.monitor] INFO: [ocr] EasyOCR 子进程就绪
728:2026-08-08 21:27:11,246 [msgbot.monitor] DEBUG: [ocr] 已截断崩溃日志,清除旧条目
729:2026-08-08 21:27:11,593 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
775:2026-08-08 21:27:14,355 [msgbot.monitor] WARNING: [mem-watch] RSS=713MB threads=37 gdi=119 hash=2 seen=0 garbage={'qq': 0, 'wechat': 0} easyocr_alive=True
784:2026-08-08 21:27:22,853 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
810:2026-08-08 21:27:25,161 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
855:2026-08-08 21:27:27,839 [msgbot.monitor] DEBUG: [ocr] EasyOCR 锁竞争超时(15s),另一线程正在处理中,本次跳过(正常行为)
866:2026-08-08 21:27:27,982 [msgbot.monitor] DEBUG: [ocr] EasyOCR 连续3次超时,杀子进程重来
874:2026-08-08 21:27:28,633 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(连续超时): terminate 后正常退出
875:2026-08-08 21:27:28,633 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(连续超时) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:27:18.949094,距现在9.0s)
899:2026-08-08 21:27:28,909 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
908:2026-08-08 21:27:31,079 [msgbot.monitor] WARNING: [wechat] EasyOCR 超时(10.0s)线程存活,跳过
912:2026-08-08 21:27:31,089 [msgbot.monitor] WARNING: [qq] Windows OCR 超时(10.0s)线程存活,跳过
913:2026-08-08 21:27:31,089 [msgbot.monitor] WARNING: [qq] EasyOCR 超时(10.0s)线程存活,跳过
914:2026-08-08 21:27:31,090 [msgbot.monitor] DEBUG: [ocr] EasyOCR 第1次启动失败,冷却(-1786195651s)
916:2026-08-08 21:27:34,032 [msgbot.monitor] ERROR: [ocr] EasyOCR worker 启动即崩溃:
917:2026-08-08 21:27:34,032 [msgbot.monitor] WARNING: [ocr] 检测到静默原生崩溃(无日志), 累计1次,下次可能强制 CPU
918:2026-08-08 21:27:34,032 [msgbot.monitor] DEBUG: [ocr] EasyOCR 冷却中(30s),跳过
919:2026-08-08 21:27:34,063 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(stop): terminate 后正常退出
920:2026-08-08 21:27:34,063 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(stop) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:27:18.949094,距现在14.6s)
921:2026-08-08 21:27:34,149 [msgbot.monitor] INFO: 消息监控已停止
923:2026-08-08 21:27:34,178 [msgbot.monitor] WARNING: [mem-watch] RSS=683MB threads=30 gdi=119 hash=0 seen=0 garbage={} easyocr_alive=False
924:2026-08-08 21:27:34,178 [msgbot.monitor] INFO: [mem-watch] 内存看门狗已启动(每30s记录 RSS/线程/GDI)
927:2026-08-08 21:27:34,180 [msgbot.monitor] INFO: 消息监控已启动
931:2026-08-08 21:27:35,220 [msgbot.monitor] DEBUG: [ocr] EasyOCR 子进程已启动,等待初始化握手...
937:2026-08-08 21:27:39,510 [msgbot.monitor] ERROR: [ocr] EasyOCR worker 启动即崩溃:
938:2026-08-08 21:27:39,511 [msgbot.monitor] WARNING: [ocr] 检测到静默原生崩溃(无日志), 累计1次,下次可能强制 CPU
939:2026-08-08 21:27:39,539 [msgbot.monitor] DEBUG: [ocr] 杀 EasyOCR 子进程(stop): terminate 后正常退出
940:2026-08-08 21:27:39,539 [msgbot.monitor] WARNING: [ocr] 杀 EasyOCR 子进程(stop) 诊断: worker死前状态=busy(模式CPU, 上次img长度76816, 更新于2026-08-08T21:27:18.949094,距现在20.0s)
941:2026-08-08 21:27:39,636 [msgbot.monitor] INFO: 消息监控已停止
+4 -2
View File
@@ -346,8 +346,8 @@ def _clean_query_for_kb(msg: str) -> str:
t = msg.strip() t = msg.strip()
# 1. 移除QQ群头衔格式: [头衔]用户名 / 【头衔】用户名 # 1. 移除QQ群头衔格式: [头衔]用户名 / 【头衔】用户名
t = re.sub(r'[\[【][^】\]]+[】\]]\s*(?:[A-Za-z0-9_\u4e00-\u9fff]{2,30})\s*[,,]?\s*', '', t) t = re.sub(r'[\[【][^】\]]+[】\]]\s*(?:[A-Za-z0-9_\u4e00-\u9fff]{2,30})\s*[,,]?\s*', '', t)
# 2. 移除@提及: @username # 2. 移除@提及: @username (仅后接空白/串尾时移除,防贪吃无空格的问句)
t = re.sub(r'@[A-Za-z0-9_\u4e00-\u9fff]{2,30}\s*', '', t) t = re.sub(r'@[A-Za-z0-9_\u4e00-\u9fff]{2,20}(?=\s|$)', '', t)
# 3. 移除时间戳: HH:MM:SS / HH:MM / 日期格式 # 3. 移除时间戳: HH:MM:SS / HH:MM / 日期格式
t = re.sub(r'\d{1,2}[::]\d{2}(?:[::]\d{2})?\s*', '', t) t = re.sub(r'\d{1,2}[::]\d{2}(?:[::]\d{2})?\s*', '', t)
t = re.sub(r'\d{4}[//\-]\d{1,2}[//\-]\d{1,2}\s*', '', t) t = re.sub(r'\d{4}[//\-]\d{1,2}[//\-]\d{1,2}\s*', '', t)
@@ -360,6 +360,8 @@ def _clean_query_for_kb(msg: str) -> str:
t = t.replace(nick, '') t = t.replace(nick, '')
except Exception: except Exception:
pass pass
# 4a. 清理孤立@前缀(昵称移除后@username变成@残余)
t = re.sub(r'^@\s*', '', t)
# 5. 清理残留标点/空格 # 5. 清理残留标点/空格
t = re.sub(r'[,,、\s]+', ' ', t).strip(',,、 \t') t = re.sub(r'[,,、\s]+', ' ', t).strip(',,、 \t')
return t return t
+15 -2
View File
@@ -3819,7 +3819,8 @@ class MessageMonitor:
has_q = any(w in line for w in _q_words) has_q = any(w in line for w in _q_words)
# ⭐ 2026-08-11: 规则4剥离")昵称 "前缀的行(如"关于我们")是真实用户消息, # ⭐ 2026-08-11: 规则4剥离")昵称 "前缀的行(如"关于我们")是真实用户消息,
# 豁免短句检查——否则规则4放行+前缀剥离全白做,消息仍被此规则丢弃。 # 豁免短句检查——否则规则4放行+前缀剥离全白做,消息仍被此规则丢弃。
if not has_q and line not in _ui_prefix_stripped: # ⭐ 2026-08-12: 包含括号的消息(如"端0(基岩版)")可能是有效短消息,放行
if not has_q and line not in _ui_prefix_stripped and not re.search(r'[()()]', line):
logger.debug(f"[{platform}] OCR 过滤: 短句碎片(≤8字无问词) line={line!r}") logger.debug(f"[{platform}] OCR 过滤: 短句碎片(≤8字无问词) line={line!r}")
continue continue
# ★ 以特殊符号(~、`等)开头 → OCR把"一键"识别为"~键"等碎片 # ★ 以特殊符号(~、`等)开头 → OCR把"一键"识别为"~键"等碎片
@@ -6685,10 +6686,20 @@ class MessageMonitor:
# 4a. 全文本签名快速跳过 — OCR 输出与上轮完全相同 → 无变化,跳过 # 4a. 全文本签名快速跳过 — OCR 输出与上轮完全相同 → 无变化,跳过
sig = "||".join([t.strip() for t in texts if t.strip()]) sig = "||".join([t.strip() for t in texts if t.strip()])
if sig == self._last_sig.get(platform, ""): if sig == self._last_sig.get(platform, ""):
# 检查是否有未回复的消息(防止未回复消息被永久跳过)
unreplied_texts = [t for t in texts if t.strip() and t.strip() not in self._replied_texts]
if not unreplied_texts:
# 所有消息均已回复,正常跳过
stale = self._stale_count.get(platform, 0) + 1 stale = self._stale_count.get(platform, 0) + 1
self._stale_count[platform] = stale self._stale_count[platform] = stale
logger.debug(f"[{platform}] Poll: 签名相同(#{stale})静默跳过: {sig[:60]!r}") logger.debug(f"[{platform}] Poll: 签名相同(#{stale})静默跳过: {sig[:60]!r}")
return return
else:
# 有未回复消息,继续处理(不跳过)
logger.info(f"[{platform}] Poll: 签名相同但有{len(unreplied_texts)}条未回复消息,继续处理: {[t[:30] for t in unreplied_texts]}")
# 仍然更新 stale 计数器,但不 return
stale = self._stale_count.get(platform, 0) + 1
self._stale_count[platform] = stale
# 4. 用全局 _seen_messages 去重(跨平台、跨轮次防回环) # 4. 用全局 _seen_messages 去重(跨平台、跨轮次防回环)
# 精确匹配 + 模糊匹配(OCR 噪声导致精确匹配失效) # 精确匹配 + 模糊匹配(OCR 噪声导致精确匹配失效)
@@ -6972,7 +6983,9 @@ class MessageMonitor:
continue continue
# 模糊匹配:OCR 输出每次微小差异(勖彐碎片、行首数字、尾部截断) # 模糊匹配:OCR 输出每次微小差异(勖彐碎片、行首数字、尾部截断)
# 精确匹配命中不了 → 用 difflib 相似度去重 # 精确匹配命中不了 → 用 difflib 相似度去重
if self._fuzzy_duplicate(ts, seen, threshold=0.80): # ⭐ 2026-08-12: 包含问号的问句(如"PHP用户端有哪两种登录模式?")不视为模糊重复
# 用户可能重复问相同问题,允许再次处理
if not re.search(r'[??]', ts) and self._fuzzy_duplicate(ts, seen, threshold=0.80):
logger.debug(f"[{platform}] 模糊重复跳过: {ts[:50]}") logger.debug(f"[{platform}] 模糊重复跳过: {ts[:50]}")
continue continue
# 超长文本(>200字符)跳过——大概率是堆积历史或 bot 自己的回复,不是单条新消息 # 超长文本(>200字符)跳过——大概率是堆积历史或 bot 自己的回复,不是单条新消息
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env python3
"""
实时监控msgbot日志 - 诊断两个问题:
1. 知识库匹配错误(牛头不对马嘴)
2. OCR连续性问题(需要表情包/图片清屏才能触发OCR)
使用方法:
1. 先启动msgbot
2. 运行此脚本开始监控
3. 在QQ/微信中发送消息测试
4. 实时查看分析结果
"""
import re
import time
import sys
from collections import defaultdict
from datetime import datetime
from pathlib import Path
class LogAnalyzer:
def __init__(self):
self.kb_matches = []
self.ocr_events = []
self.pixel_stats = []
self.replies = []
def analyze_line(self, line: str):
"""分析单行日志"""
line = line.strip()
if not line:
return
# 分析KB匹配
if "KB搜索输入" in line:
self.kb_matches.append({
'time': datetime.now(),
'type': 'search_input',
'content': line
})
# 分析KB结果
elif "KB结果" in line and "标题" in line:
self.kb_matches.append({
'time': datetime.now(),
'type': 'search_result',
'content': line
})
# 分析内容相关性
elif "内容相关性检查" in line:
self.kb_matches.append({
'time': datetime.now(),
'type': 'relevance_check',
'content': line
})
# 分析像素检测
elif "像素统计" in line or "像素检测" in line:
self.pixel_stats.append({
'time': datetime.now(),
'content': line
})
# 分析OCR事件
elif "OCR" in line and ("跳过" in line or "触发" in line or "输出" in line):
self.ocr_events.append({
'time': datetime.now(),
'content': line
})
# 分析回复
elif "新消息" in line and ("回复" in line or "发送" in line):
self.replies.append({
'time': datetime.now(),
'content': line
})
def print_summary(self):
"""打印分析摘要"""
print("\n" + "="*80)
print(f"分析摘要 - {datetime.now().strftime('%H:%M:%S')}")
print("="*80)
# KB匹配分析
print(f"\n【知识库匹配】共 {len(self.kb_matches)} 条记录")
if self.kb_matches:
print(" 最近5条:")
for item in self.kb_matches[-5:]:
print(f" [{item['time'].strftime('%H:%M:%S')}] {item['content'][:80]}")
# 像素检测分析
print(f"\n【像素检测】共 {len(self.pixel_stats)} 条记录")
if self.pixel_stats:
print(" 最近5条:")
for item in self.pixel_stats[-5:]:
print(f" [{item['time'].strftime('%H:%M:%S')}] {item['content'][:80]}")
# OCR事件分析
print(f"\n【OCR事件】共 {len(self.ocr_events)} 条记录")
if self.ocr_events:
print(" 最近5条:")
for item in self.ocr_events[-5:]:
print(f" [{item['time'].strftime('%H:%M:%S')}] {item['content'][:80]}")
# 回复分析
print(f"\n【回复记录】共 {len(self.replies)} 条记录")
if self.replies:
print(" 最近5条:")
for item in self.replies[-5:]:
print(f" [{item['time'].strftime('%H:%M:%S')}] {item['content'][:80]}")
print("="*80)
def monitor_log_file(log_file: str):
"""监控日志文件"""
print(f"开始监控日志文件: {log_file}")
print("按 Ctrl+C 停止监控")
print("-"*80)
analyzer = LogAnalyzer()
try:
with open(log_file, 'r', encoding='utf-8', errors='ignore') as f:
# 跳到文件末尾
f.seek(0, 2)
while True:
line = f.readline()
if not line:
time.sleep(0.1)
continue
analyzer.analyze_line(line)
print(line.rstrip())
# 每30秒打印一次摘要
if int(time.time()) % 30 == 0:
analyzer.print_summary()
except KeyboardInterrupt:
print("\n监控已停止")
analyzer.print_summary()
except FileNotFoundError:
print(f"日志文件不存在: {log_file}")
print("请先启动msgbot,然后运行此脚本")
def main():
"""主函数"""
# 查找最新的日志文件
log_patterns = [
"msgbot.log",
"monitor.log",
"debug.log",
"*.log"
]
log_files = []
for pattern in log_patterns:
log_files.extend(list(Path(".").glob(pattern)))
if not log_files:
print("未找到日志文件,请先启动msgbot")
print("然后运行此脚本开始监控")
return
print("找到以下日志文件:")
for i, f in enumerate(log_files, 1):
print(f" {i}. {f.name}")
print("\n监控功能说明:")
print("1. 实时显示日志内容")
print("2. 自动分析KB匹配过程")
print("3. 跟踪像素检测结果")
print("4. 记录OCR事件")
print("5. 监控回复发送")
# 选择要监控的文件
if len(log_files) == 1:
monitor_log_file(str(log_files[0]))
else:
try:
choice = int(input("\n请选择要监控的日志文件编号: ")) - 1
if 0 <= choice < len(log_files):
monitor_log_file(str(log_files[choice]))
else:
print("无效的选择")
except ValueError:
print("请输入有效的数字")
if __name__ == "__main__":
main()