feat:识别群昵称

This commit is contained in:
2025-12-23 16:46:41 +08:00
parent cc250e1f1e
commit 2c564d2870
6 changed files with 320 additions and 15 deletions

View File

@@ -4,7 +4,9 @@ HookBot - 机器人核心类
处理消息路由和事件分发
"""
import asyncio
import tomllib
import time
from typing import Dict, Any
from loguru import logger
@@ -52,6 +54,12 @@ class HookBot:
perf_config = main_config.get("Performance", {})
self.log_sampling_rate = perf_config.get("log_sampling_rate", 1.0)
# 消息去重(部分环境会重复回调同一条消息,导致插件回复两次)
self._dedup_ttl_seconds = perf_config.get("dedup_ttl_seconds", 30)
self._dedup_max_size = perf_config.get("dedup_max_size", 5000)
self._dedup_lock = asyncio.Lock()
self._recent_message_keys: Dict[str, float] = {}
# 消息计数和统计
self.message_count = 0
self.filtered_count = 0
@@ -59,6 +67,54 @@ class HookBot:
logger.info("HookBot 初始化完成")
def _extract_msg_id(self, data: Dict[str, Any]) -> str:
"""从原始回调数据中提取消息ID用于去重"""
for k in ("msgid", "msg_id", "MsgId", "id"):
v = data.get(k)
if v:
return str(v)
return ""
async def _is_duplicate_message(self, msg_type: int, data: Dict[str, Any]) -> bool:
"""判断该条消息是否为短时间内重复回调。"""
msg_id = self._extract_msg_id(data)
if not msg_id:
# 没有稳定 msgid 时不做去重,避免误伤(同一秒内同内容可能是用户真实重复发送)
return False
key = f"msgid:{msg_id}"
now = time.time()
ttl = max(float(self._dedup_ttl_seconds or 0), 0.0)
if ttl <= 0:
return False
async with self._dedup_lock:
last_seen = self._recent_message_keys.get(key)
if last_seen is not None and (now - last_seen) < ttl:
return True
# 记录/刷新
self._recent_message_keys.pop(key, None)
self._recent_message_keys[key] = now
# 清理过期 key按插入顺序从旧到新
cutoff = now - ttl
while self._recent_message_keys:
first_key = next(iter(self._recent_message_keys))
if self._recent_message_keys.get(first_key, now) >= cutoff:
break
self._recent_message_keys.pop(first_key, None)
# 限制大小,避免长期运行内存增长
max_size = int(self._dedup_max_size or 0)
if max_size > 0:
while len(self._recent_message_keys) > max_size and self._recent_message_keys:
first_key = next(iter(self._recent_message_keys))
self._recent_message_keys.pop(first_key, None)
return False
def update_profile(self, wxid: str, nickname: str):
"""
更新机器人信息
@@ -80,9 +136,20 @@ class HookBot:
data: 消息数据
"""
# 过滤 API 响应消息
if msg_type in [11174, 11230]:
# - 11032: 获取群成员信息响应
# - 11174/11230: 协议/上传等 API 回调
if msg_type in [11032, 11174, 11230]:
return
# 去重:同一条消息重复回调时不再重复触发事件(避免“同一句话回复两次”)
try:
if await self._is_duplicate_message(msg_type, data):
logger.debug(f"[HookBot] 重复消息已丢弃: type={msg_type}, msgid={self._extract_msg_id(data) or 'N/A'}")
return
except Exception as e:
# 去重失败不影响主流程
logger.debug(f"[HookBot] 消息去重检查失败: {e}")
# 消息计数
self.message_count += 1