修复2个bug: 同poll取最新消息(末条) + 斜线I变形(Iskin)过滤

Bug1 - 用户问寻宝奖励,bot回复sdf1导入错误:
  OCR从上到下读屏,旧消息排前面新消息排后面。
  原逻辑'只处理第一条'把旧历史消息当新消息处理,
  真正的用户新消息被'同poll第条跳过'挡掉。
  修复:改为取new_items[-1](最后一条=屏幕最下方=最新消息),
  其余加入seen防重复。

Bug2 - /skin OCR变形为Iskin在消息中后段未被过滤:
  /skin→OCR→Iskin(I替代/)。原过滤器要求^[A-Za-z]开头
  且len>10,但'使用指令Iskin'=9字符→漏网。
  修复:新增CJK+I+小写字母变形过滤器[\u4e00-\u9fff]I[a-z]{2,},
  拦截所有CJK上下文中的斜线I变形命令。
This commit is contained in:
youpaishidifu
2026-07-30 13:04:30 +08:00
parent 18d7880a49
commit e9bccb688b
+21 -15
View File
@@ -3547,6 +3547,12 @@ class MessageMonitor:
if 'sdfl' in ts.lower() or 'sdf1' in ts.lower(): if 'sdfl' in ts.lower() or 'sdf1' in ts.lower():
logger.debug(f"[{platform}] Poll过滤: 变形命令(sdfl) ts={ts!r}") logger.debug(f"[{platform}] Poll过滤: 变形命令(sdfl) ts={ts!r}")
continue continue
# === OCR 斜线→I 变形:/skin→Iskin, /reg→Ireg 等 ===
# 特征:CJK 上下文中出现 I+小写字母(正常中文聊天不会这样写)
# 用户不会发"使用指令Iskin"这种文本,安全砍掉不进知识库
if re.search(r'[\u4e00-\u9fff]I[a-z]{2,}', ts):
logger.debug(f"[{platform}] Poll过滤: 斜线I变形 ts={ts!r}")
continue
if re.match(r'^[A-Z][a-z]{4,}', ts) and re.search(r'[\u4e00-\u9fff]', ts) and len(ts) > 10: if re.match(r'^[A-Z][a-z]{4,}', ts) and re.search(r'[\u4e00-\u9fff]', ts) and len(ts) > 10:
logger.debug(f"[{platform}] Poll过滤: 变形命令(大写+字母) ts={ts!r}") logger.debug(f"[{platform}] Poll过滤: 变形命令(大写+字母) ts={ts!r}")
continue continue
@@ -3698,25 +3704,25 @@ class MessageMonitor:
if now - v < 60.0 if now - v < 60.0
} }
# 有纯粹的新文本 → 逐一报告(同平台同一 poll 内只处理第一条) # ⭐ 取最后一条(屏幕最下方 = 最新消息)
first = True # OCR 从上到下读屏,旧消息排前面,新消息排后面。
# 原"只处理第一条"逻辑把旧历史消息当新消息处理,
# 真正的用户新消息被"同poll第条跳过"挡掉。
item = new_items[-1]
if len(new_items) > 1:
logger.debug(f"[{platform}] 同poll多条({len(new_items)}条),取最后(最新): {item[:40]}")
# 其余加入 seen 防止下次重复
for skipped in new_items[:-1]:
seen.add(skipped)
# ⭐ 首次成功轮询(上次无消息→本次有消息):拦截历史基线 # ⭐ 首次成功轮询(上次无消息→本次有消息):拦截历史基线
is_baseline = self._last_new_msg_time.get(platform, 0) == 0 is_baseline = self._last_new_msg_time.get(platform, 0) == 0
if is_baseline: if is_baseline:
logger.info(f"[{platform}] 首次消息→基线拦截({len(new_items)}条): {new_items[0][:60]}") # 基线轮:日志标记但不触发回复,添加到 seen 防止下次再来
logger.info(f"[{platform}] 基线↺(不回复): {item[:60]}")
for item in new_items: seen.add(item)
if not first: self._last_new_msg_time[platform] = time.time()
logger.debug(f"[{platform}] 同poll第条,跳过防多发: {item[:40]}") else:
continue
first = False # 只处理第一条
if is_baseline:
# 基线轮:日志标记但不触发回复,添加到 seen 防止下次再来
logger.info(f"[{platform}] 基线↺(不回复): {item[:60]}")
seen.add(item)
self._last_new_msg_time[platform] = time.time()
continue
self._last_new_msg_time[platform] = time.time() self._last_new_msg_time[platform] = time.time()
self._last_msg[platform] = item self._last_msg[platform] = item
engine_tag = self._last_chosen_engine.get(platform, "") engine_tag = self._last_chosen_engine.get(platform, "")