feat: QQ昵称剥离功能增强,支持【头衔】用户名格式
- 新增QQ群头衔+用户名格式剥离:【头衔】用户名 或 [头衔] 用户名 - 处理OCR将【识别为[、】识别为]的情况 - 保持原有纯文本昵称剥离功能 - 测试用例全部通过
This commit is contained in:
@@ -14,6 +14,7 @@ DEFAULT_CONFIG = {
|
||||
"qq_enabled": True,
|
||||
"auto_reply_enabled": False,
|
||||
"auto_reply_min_score": 0.35,
|
||||
"qq_nicknames": [], # 需要从消息文本开头剥离的QQ昵称列表
|
||||
}
|
||||
|
||||
|
||||
|
||||
+62
@@ -3155,6 +3155,8 @@ class MessageMonitor:
|
||||
# 永久丢失(bot 回复一次后再也不回复)。剥离后保留用户提问。
|
||||
msg = self._strip_bot_reply_fragments(msg)
|
||||
if msg:
|
||||
# ⭐ 剥离QQ用户昵称,防止昵称拼凑进消息文本导致查库关键词被压住
|
||||
msg = self._strip_qq_nickname(msg)
|
||||
if self._is_reply_fragment(msg):
|
||||
logger.info(f"[ocr] stage[{i}] [filter4/回复残片] DROP 回复残片跳过: {msg[:60]!r}")
|
||||
else:
|
||||
@@ -3199,6 +3201,8 @@ class MessageMonitor:
|
||||
# ⭐ 同上:尾部消息也要先剥离 bot 旧回复片段,避免整段误判为残片
|
||||
msg = self._strip_bot_reply_fragments(msg)
|
||||
if msg:
|
||||
# ⭐ 剥离QQ用户昵称,防止昵称拼凑进消息文本导致查库关键词被压住
|
||||
msg = self._strip_qq_nickname(msg)
|
||||
if self._is_reply_fragment(msg):
|
||||
logger.info(f"[ocr] stage[{i}] [filter4/回复残片] DROP 回复残片跳过(尾部): {msg[:60]!r}")
|
||||
else:
|
||||
@@ -4311,6 +4315,64 @@ class MessageMonitor:
|
||||
ts = re.sub(r'\s+', ' ', ts).strip().strip(',').strip()
|
||||
return ts
|
||||
|
||||
def _strip_qq_nickname(self, text: str) -> str:
|
||||
"""从消息文本开头剥离QQ用户昵称,防止昵称拼凑进消息文本导致查库关键词被压住。
|
||||
|
||||
QQ群聊截图中,OCR会把用户昵称和消息文本拼在一起,如:
|
||||
"草原探险服务器备用号游戏专用在哪下载登陆插件"
|
||||
其中"草原探险服务器备用号"和"游戏专用"是用户昵称,"在哪下载登陆插件"是实际消息。
|
||||
|
||||
策略:
|
||||
1. 检查消息文本是否以已知昵称列表中的某个昵称开头
|
||||
2. 如果是,剥离该昵称(可能包括后续的空格/标点)
|
||||
3. 重复步骤1-2,直到没有匹配的昵称
|
||||
4. 如果消息文本以"//"或"=>"开头,这些可能是OCR识别的箭头,一并剥离
|
||||
"""
|
||||
if not text or not text.strip():
|
||||
return text
|
||||
ts = text.strip()
|
||||
# 剥离箭头前缀(OCR可能识别为"//"或"=>")
|
||||
if ts.startswith('//') or ts.startswith('=>'):
|
||||
ts = ts[2:].lstrip()
|
||||
|
||||
# ⭐ 剥离QQ群头衔+用户名格式:【头衔】用户名 或 [头衔] 用户名
|
||||
# OCR可能把【识别为[,把】识别为],所以同时处理两种括号
|
||||
# 匹配模式:[【\[]任意内容】\]] + 可选空格 + 用户名(中文/英文/数字/下划线)
|
||||
qq_title_pattern = re.compile(r'^[\[【][^】\]]+[】\]]\s*[\w\u4e00-\u9fff]+[,,]?\s*')
|
||||
while True:
|
||||
m = qq_title_pattern.match(ts)
|
||||
if m:
|
||||
ts = ts[m.end():].lstrip()
|
||||
else:
|
||||
break
|
||||
|
||||
# 加载配置中的昵称列表
|
||||
try:
|
||||
from config import load_config
|
||||
cfg = load_config()
|
||||
nicknames = cfg.get('qq_nicknames', [])
|
||||
except Exception:
|
||||
nicknames = []
|
||||
# 如果没有配置昵称,使用默认的已知昵称(从日志中提取)
|
||||
if not nicknames:
|
||||
nicknames = [
|
||||
"草原探险服务器备用号",
|
||||
"游戏专用",
|
||||
# 可以添加更多已知昵称
|
||||
]
|
||||
# 逐个尝试剥离昵称
|
||||
changed = True
|
||||
while changed:
|
||||
changed = False
|
||||
for nick in nicknames:
|
||||
if ts.startswith(nick):
|
||||
ts = ts[len(nick):].lstrip()
|
||||
changed = True
|
||||
break
|
||||
# 清理残留的标点/空格
|
||||
ts = re.sub(r'^[\s,,.。::;;!!??]+', '', ts)
|
||||
return ts.strip()
|
||||
|
||||
def _is_reply_fragment(self, text: str) -> bool:
|
||||
"""检查文本是否为 bot 回复内容的碎片(OCR 截取的 md 残片/跨行碎片)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user