From bd46b932e6fe247d59f1a776a1103dfc12814c71 Mon Sep 17 00:00:00 2001 From: clown145 Date: Thu, 12 Feb 2026 01:36:48 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=B9=E9=BD=90QQ=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=B9=B6=E5=8E=BB=E9=87=8DTelegram=E6=96=87=E6=9C=AC=E4=B8=AD?= =?UTF-8?q?=E7=9A=84@?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/main.py b/main.py index ea672d0..15b10c4 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,8 @@ QQ群日常分析插件 import asyncio import os +import re +from collections import Counter from astrbot.api import AstrBotConfig, logger from astrbot.api.event import AstrMessageEvent, filter @@ -366,6 +368,29 @@ class QQGroupDailyAnalysis(Star): message_parts = [] message = event.message_obj + # 先收集 @ 标记,后续用于从 plain 文本中去重 + pending_mentions: Counter[str] = Counter() + if message and hasattr(message, "message"): + for seg in message.message: + if not hasattr(seg, "type"): + continue + if seg.type not in ("At", "at"): + continue + + target = getattr(seg, "target", None) + if target is None: + target = getattr(seg, "qq", None) + if target is None and hasattr(seg, "data"): + target = seg.data.get("qq") or seg.data.get("target") + + target_str = str(target or "").strip() + if target_str: + pending_mentions[target_str] += 1 + + display_name = str(getattr(seg, "name", "") or "").strip() + if display_name and display_name != target_str: + pending_mentions[display_name] += 1 + if message and hasattr(message, "message"): for seg in message.message: if not hasattr(seg, "type"): @@ -377,6 +402,7 @@ class QQGroupDailyAnalysis(Star): if text is None and hasattr(seg, "data"): text = seg.data.get("text") if text: + text = self._strip_known_mentions(text, pending_mentions) message_parts.append({"type": "plain", "text": text}) elif seg_type in ("Image", "image"): @@ -405,8 +431,46 @@ class QQGroupDailyAnalysis(Star): if not message_parts and event.message_str: message_parts.append({"type": "plain", "text": event.message_str}) + # 清理空文本段,避免出现仅空格文本 + message_parts = [ + part + for part in message_parts + if not ( + part.get("type") == "plain" and not str(part.get("text", "")).strip() + ) + ] + return message_parts + @staticmethod + def _strip_known_mentions(text: str, pending_mentions: Counter[str]) -> str: + """ + 从文本中移除已识别的 @ 提及,避免与结构化 at 段重复。 + """ + cleaned = str(text) + if not cleaned or not pending_mentions: + return cleaned.strip() + + for mention, remaining in list(pending_mentions.items()): + if not mention or remaining <= 0: + continue + + pattern = re.compile(rf"(? 0: + pending_mentions[mention] -= removed + if pending_mentions[mention] <= 0: + pending_mentions.pop(mention, None) + + cleaned = re.sub(r"\s{2,}", " ", cleaned).strip() + return cleaned + # ==================== Telegram 消息拦截器 ==================== @filter.event_message_type(filter.EventMessageType.GROUP_MESSAGE)