From 03c35f49d0d8876f194071593eebd2dfd7f49863 Mon Sep 17 00:00:00 2001 From: Helian Nuits Date: Tue, 25 Nov 2025 23:37:13 +0800 Subject: [PATCH] =?UTF-8?q?Fix(bot=20manager):=20=5Fget=5Fplatform=5Fid=5F?= =?UTF-8?q?for=5Fgroup=20=E6=98=AF=E4=B8=80=E4=B8=AA=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=88async=20def=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E4=BD=86=E5=9C=A8=20main.py=20=E4=B8=AD=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=97=B6=E5=BF=98=E8=AE=B0=E5=8A=A0=20await=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(bot-manager): 正确处理实例获取 * fix(import); AiocqhttpAdapter 导入 * fix: 通过 meta 实现 aiocqhttp 判断 * fix(_get_platform_id_for_group): _get_platform_id_for_group 是一个异步方法(async def),但在 main.py 中调用时忘记加 await 了,导致它返回了一个协程对象而不是字符串 ID * fix(pre-commit) --- main.py | 12 +++--- src/analysis/analyzers/__init__.py | 2 +- src/analysis/analyzers/base_analyzer.py | 4 +- .../analyzers/golden_quote_analyzer.py | 6 ++- src/analysis/analyzers/topic_analyzer.py | 8 ++-- src/analysis/analyzers/user_title_analyzer.py | 5 ++- src/analysis/llm_analyzer.py | 8 ++-- src/analysis/statistics.py | 3 +- src/analysis/utils/__init__.py | 12 +++--- src/analysis/utils/json_utils.py | 1 + src/analysis/utils/llm_utils.py | 1 + src/core/bot_manager.py | 40 +++++++++++++------ src/core/config.py | 3 +- src/core/message_handler.py | 6 ++- src/models/__init__.py | 6 +-- src/reports/generators.py | 14 ++++--- src/reports/templates.py | 4 +- src/scheduler/auto_scheduler.py | 11 +++-- src/utils/__init__.py | 2 +- src/utils/helpers.py | 7 ++-- src/utils/pdf_utils.py | 3 +- src/visualization/activity_charts.py | 3 +- 22 files changed, 98 insertions(+), 63 deletions(-) diff --git a/main.py b/main.py index 6c84485..172766c 100644 --- a/main.py +++ b/main.py @@ -7,23 +7,23 @@ QQ群日常分析插件 import asyncio +from astrbot.api import AstrBotConfig, logger from astrbot.api.event import filter from astrbot.api.star import Context, Star -from astrbot.api import logger, AstrBotConfig +from astrbot.core.message.components import File from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_message_event import ( AiocqhttpMessageEvent, ) -from astrbot.core.message.components import File from astrbot.core.star.filter.permission import PermissionType +from .src.core.bot_manager import BotManager + # 导入重构后的模块 from .src.core.config import ConfigManager -from .src.core.bot_manager import BotManager from .src.reports.generators import ReportGenerator from .src.scheduler.auto_scheduler import AutoScheduler -from .src.utils.pdf_utils import PDFInstaller from .src.utils.helpers import MessageAnalyzer - +from .src.utils.pdf_utils import PDFInstaller # 全局变量 config_manager = None @@ -175,7 +175,7 @@ class QQGroupDailyAnalysis(Star): try: # 获取该群对应的平台ID和bot实例 - platform_id = auto_scheduler._get_platform_id_for_group(group_id) + platform_id = await auto_scheduler._get_platform_id_for_group(group_id) bot_instance = bot_manager.get_bot_instance(platform_id) if not bot_instance: diff --git a/src/analysis/analyzers/__init__.py b/src/analysis/analyzers/__init__.py index fe370dd..d64cf46 100644 --- a/src/analysis/analyzers/__init__.py +++ b/src/analysis/analyzers/__init__.py @@ -4,8 +4,8 @@ """ from .base_analyzer import BaseAnalyzer +from .golden_quote_analyzer import GoldenQuoteAnalyzer from .topic_analyzer import TopicAnalyzer from .user_title_analyzer import UserTitleAnalyzer -from .golden_quote_analyzer import GoldenQuoteAnalyzer __all__ = ["BaseAnalyzer", "TopicAnalyzer", "UserTitleAnalyzer", "GoldenQuoteAnalyzer"] diff --git a/src/analysis/analyzers/base_analyzer.py b/src/analysis/analyzers/base_analyzer.py index a75faa5..ad3ae6e 100644 --- a/src/analysis/analyzers/base_analyzer.py +++ b/src/analysis/analyzers/base_analyzer.py @@ -5,13 +5,15 @@ from abc import ABC, abstractmethod from typing import Any + from astrbot.api import logger + from ...models.data_models import TokenUsage from ..utils.json_utils import parse_json_response from ..utils.llm_utils import ( call_provider_with_retry, - extract_token_usage, extract_response_text, + extract_token_usage, ) diff --git a/src/analysis/analyzers/golden_quote_analyzer.py b/src/analysis/analyzers/golden_quote_analyzer.py index a772595..e7587c8 100644 --- a/src/analysis/analyzers/golden_quote_analyzer.py +++ b/src/analysis/analyzers/golden_quote_analyzer.py @@ -4,11 +4,13 @@ """ from datetime import datetime + from astrbot.api import logger + from ...models.data_models import GoldenQuote, TokenUsage -from .base_analyzer import BaseAnalyzer -from ..utils.json_utils import extract_golden_quotes_with_regex from ..utils import InfoUtils +from ..utils.json_utils import extract_golden_quotes_with_regex +from .base_analyzer import BaseAnalyzer class GoldenQuoteAnalyzer(BaseAnalyzer): diff --git a/src/analysis/analyzers/topic_analyzer.py b/src/analysis/analyzers/topic_analyzer.py index 5cc5873..93e90cf 100644 --- a/src/analysis/analyzers/topic_analyzer.py +++ b/src/analysis/analyzers/topic_analyzer.py @@ -3,13 +3,15 @@ 专门处理群聊话题分析 """ -from datetime import datetime import re +from datetime import datetime + from astrbot.api import logger + from ...models.data_models import SummaryTopic, TokenUsage -from .base_analyzer import BaseAnalyzer -from ..utils.json_utils import extract_topics_with_regex from ..utils import InfoUtils +from ..utils.json_utils import extract_topics_with_regex +from .base_analyzer import BaseAnalyzer class TopicAnalyzer(BaseAnalyzer): diff --git a/src/analysis/analyzers/user_title_analyzer.py b/src/analysis/analyzers/user_title_analyzer.py index c654e25..8a0a46b 100644 --- a/src/analysis/analyzers/user_title_analyzer.py +++ b/src/analysis/analyzers/user_title_analyzer.py @@ -4,9 +4,10 @@ """ from astrbot.api import logger -from ...models.data_models import UserTitle, TokenUsage -from .base_analyzer import BaseAnalyzer + +from ...models.data_models import TokenUsage, UserTitle from ..utils.json_utils import extract_user_titles_with_regex +from .base_analyzer import BaseAnalyzer class UserTitleAnalyzer(BaseAnalyzer): diff --git a/src/analysis/llm_analyzer.py b/src/analysis/llm_analyzer.py index 59eccb3..17cf3bd 100644 --- a/src/analysis/llm_analyzer.py +++ b/src/analysis/llm_analyzer.py @@ -4,13 +4,15 @@ LLM分析器模块 """ import asyncio + from astrbot.api import logger -from ..models.data_models import SummaryTopic, UserTitle, GoldenQuote, TokenUsage + +from ..models.data_models import GoldenQuote, SummaryTopic, TokenUsage, UserTitle +from .analyzers.golden_quote_analyzer import GoldenQuoteAnalyzer from .analyzers.topic_analyzer import TopicAnalyzer from .analyzers.user_title_analyzer import UserTitleAnalyzer -from .analyzers.golden_quote_analyzer import GoldenQuoteAnalyzer -from .utils.llm_utils import call_provider_with_retry from .utils.json_utils import fix_json +from .utils.llm_utils import call_provider_with_retry class LLMAnalyzer: diff --git a/src/analysis/statistics.py b/src/analysis/statistics.py index 8080b54..ae2ef05 100644 --- a/src/analysis/statistics.py +++ b/src/analysis/statistics.py @@ -3,8 +3,9 @@ 负责用户活跃度分析和其他统计功能 """ -from datetime import datetime from collections import defaultdict +from datetime import datetime + from .utils import InfoUtils diff --git a/src/analysis/utils/__init__.py b/src/analysis/utils/__init__.py index 8388263..651c60e 100644 --- a/src/analysis/utils/__init__.py +++ b/src/analysis/utils/__init__.py @@ -3,22 +3,20 @@ 包含JSON处理和LLM API请求处理工具 """ +from .info_utils import InfoUtils from .json_utils import ( - fix_json, - parse_json_response, + extract_golden_quotes_with_regex, extract_topics_with_regex, extract_user_titles_with_regex, - extract_golden_quotes_with_regex, + fix_json, + parse_json_response, ) - from .llm_utils import ( call_provider_with_retry, - extract_token_usage, extract_response_text, + extract_token_usage, ) -from .info_utils import InfoUtils - __all__ = [ # JSON处理工具 "fix_json", diff --git a/src/analysis/utils/json_utils.py b/src/analysis/utils/json_utils.py index 41b3d96..edf6676 100644 --- a/src/analysis/utils/json_utils.py +++ b/src/analysis/utils/json_utils.py @@ -5,6 +5,7 @@ JSON处理工具模块 import json import re + from astrbot.api import logger diff --git a/src/analysis/utils/llm_utils.py b/src/analysis/utils/llm_utils.py index 4071b7a..e527dee 100644 --- a/src/analysis/utils/llm_utils.py +++ b/src/analysis/utils/llm_utils.py @@ -5,6 +5,7 @@ LLM API请求处理工具模块 import asyncio from typing import Any + from astrbot.api import logger diff --git a/src/core/bot_manager.py b/src/core/bot_manager.py index 03bca52..59dcbf9 100644 --- a/src/core/bot_manager.py +++ b/src/core/bot_manager.py @@ -4,6 +4,7 @@ Bot实例管理模块 """ from typing import Any + from astrbot.api import logger @@ -48,19 +49,20 @@ class BotManager: """获取指定平台的bot实例,如果不指定则返回第一个可用的实例""" if platform_id: # 如果指定了平台ID,尝试获取 - instance = self._bot_instances.get(platform_id) - if instance: - return instance + return self._bot_instances.get(platform_id) - # 没有指定平台ID,返回第一个可用的实例 + # 没有指定平台ID if self._bot_instances: - first_platform = list(self._bot_instances.keys())[0] - if len(self._bot_instances) > 1: - logger.debug( - f"未指定平台,使用第一个可用平台 '{first_platform}' " - f"(共有 {len(self._bot_instances)} 个平台: {list(self._bot_instances.keys())})" - ) - return self._bot_instances[first_platform] + # 如果只有一个实例,直接返回 + if len(self._bot_instances) == 1: + return list(self._bot_instances.values())[0] + + # 如果有多个实例,必须指定 platform_id + logger.error( + f"存在多个Bot实例 {list(self._bot_instances.keys())} 但未指定 platform_id," + "无法确定使用哪个实例。请明确指定 platform_id。" + ) + return None # 没有任何平台可用 logger.error("没有任何可用的bot实例") @@ -85,14 +87,19 @@ class BotManager: return self._default_platform async def auto_discover_bot_instances(self): - """自动发现所有可用的bot实例""" + """自动发现所有可用的bot实例 (仅限 QQ/Aiocqhttp)""" if not self._context or not hasattr(self._context, "platform_manager"): return {} - platforms = getattr(self._context.platform_manager, "platform_insts", []) + # 使用新版 API 获取所有平台实例 + platforms = self._context.platform_manager.get_insts() discovered = {} for platform in platforms: + # 严格过滤:只处理 AiocqhttpAdapter (QQ) + if platform.metadata.name != "aiocqhttp": + continue + # 获取bot实例 bot_client = None if hasattr(platform, "get_client"): @@ -138,6 +145,13 @@ class BotManager: def update_from_event(self, event): """从事件更新bot实例(用于手动命令)""" + # 检查是否为 QQ 平台事件 + if ( + hasattr(event, "get_platform_name") + and event.get_platform_name() != "aiocqhttp" + ): + return False + if hasattr(event, "bot") and event.bot: # 从事件中获取平台ID platform_id = None diff --git a/src/core/config.py b/src/core/config.py index 3f1b8ea..32955cb 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -4,7 +4,8 @@ """ import sys -from astrbot.api import logger, AstrBotConfig + +from astrbot.api import AstrBotConfig, logger class ConfigManager: diff --git a/src/core/message_handler.py b/src/core/message_handler.py index cd330d5..1ba6ac5 100644 --- a/src/core/message_handler.py +++ b/src/core/message_handler.py @@ -3,10 +3,12 @@ 负责群聊消息的获取、过滤和预处理 """ -from datetime import datetime, timedelta from collections import defaultdict +from datetime import datetime, timedelta + from astrbot.api import logger -from ...src.models.data_models import GroupStatistics, TokenUsage, EmojiStatistics + +from ...src.models.data_models import EmojiStatistics, GroupStatistics, TokenUsage from ...src.visualization.activity_charts import ActivityVisualizer diff --git a/src/models/__init__.py b/src/models/__init__.py index 1630360..bc05798 100644 --- a/src/models/__init__.py +++ b/src/models/__init__.py @@ -3,11 +3,11 @@ """ from .data_models import ( - SummaryTopic, - UserTitle, GoldenQuote, - TokenUsage, GroupStatistics, + SummaryTopic, + TokenUsage, + UserTitle, ) __all__ = ["SummaryTopic", "UserTitle", "GoldenQuote", "TokenUsage", "GroupStatistics"] diff --git a/src/reports/generators.py b/src/reports/generators.py index c0d6d2d..afeb482 100644 --- a/src/reports/generators.py +++ b/src/reports/generators.py @@ -3,14 +3,17 @@ 负责生成各种格式的分析报告 """ +import asyncio import base64 -import aiohttp from datetime import datetime from pathlib import Path + +import aiohttp + from astrbot.api import logger -from .templates import HTMLTemplates + from ..visualization.activity_charts import ActivityVisualizer -import asyncio +from .templates import HTMLTemplates class ReportGenerator: @@ -310,10 +313,11 @@ class ReportGenerator: return False # 动态导入 pyppeteer + import os + import sys + import pyppeteer from pyppeteer import launch - import sys - import os # 尝试启动浏览器,如果 Chromium 不存在会自动下载 logger.info("启动浏览器进行 PDF 转换") diff --git a/src/reports/templates.py b/src/reports/templates.py index 646c7e6..548621d 100644 --- a/src/reports/templates.py +++ b/src/reports/templates.py @@ -4,9 +4,11 @@ HTML模板模块 """ import os -from astrbot.api import logger + from jinja2 import Environment, FileSystemLoader, select_autoescape +from astrbot.api import logger + class HTMLTemplates: """HTML模板管理类""" diff --git a/src/scheduler/auto_scheduler.py b/src/scheduler/auto_scheduler.py index e5fa846..911e9e4 100644 --- a/src/scheduler/auto_scheduler.py +++ b/src/scheduler/auto_scheduler.py @@ -6,6 +6,7 @@ import asyncio import weakref from datetime import datetime, timedelta + from astrbot.api import logger @@ -95,13 +96,11 @@ class AutoScheduler: ) continue - # 如果所有适配器都尝试失败,记录警告并返回第一个 - logger.warning( - f"⚠️ 无法确定群 {group_id} 属于哪个平台,使用第一个适配器" + # 如果所有适配器都尝试失败,记录错误并返回 None + logger.error( + f"❌ 无法确定群 {group_id} 属于哪个平台 (已尝试: {list(self.bot_manager._bot_instances.keys())})" ) - first_platform = list(self.bot_manager._bot_instances.keys())[0] - logger.warning(f"使用默认平台: {first_platform}") - return first_platform + return None # 没有任何bot实例,返回None logger.error("❌ 没有注册的bot实例") diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 75bef1a..9c47efd 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -3,7 +3,7 @@ 包含PDF处理和通用工具函数 """ -from .pdf_utils import PDFInstaller from .helpers import MessageAnalyzer +from .pdf_utils import PDFInstaller __all__ = ["PDFInstaller", "MessageAnalyzer"] diff --git a/src/utils/helpers.py b/src/utils/helpers.py index 3f701af..e0fb3f0 100644 --- a/src/utils/helpers.py +++ b/src/utils/helpers.py @@ -3,11 +3,12 @@ 包含消息分析和其他通用功能 """ -from ...src.models.data_models import TokenUsage -from ...src.core.message_handler import MessageHandler +from astrbot.api import logger + from ...src.analysis.llm_analyzer import LLMAnalyzer from ...src.analysis.statistics import UserAnalyzer -from astrbot.api import logger +from ...src.core.message_handler import MessageHandler +from ...src.models.data_models import TokenUsage class MessageAnalyzer: diff --git a/src/utils/pdf_utils.py b/src/utils/pdf_utils.py index 0916f8e..702b8d6 100644 --- a/src/utils/pdf_utils.py +++ b/src/utils/pdf_utils.py @@ -3,9 +3,10 @@ PDF工具模块 负责PDF相关的安装和管理功能 """ -import sys import asyncio +import sys from concurrent.futures import ThreadPoolExecutor + from astrbot.api import logger diff --git a/src/visualization/activity_charts.py b/src/visualization/activity_charts.py index a18ba3a..168544c 100644 --- a/src/visualization/activity_charts.py +++ b/src/visualization/activity_charts.py @@ -3,8 +3,9 @@ 参考 astrbot_plugin_github_analyzer 的实现方式 """ -from datetime import datetime from collections import defaultdict +from datetime import datetime + from ..models.data_models import ActivityVisualization