Fix(bot manager): _get_platform_id_for_group 是一个异步方法(async def),但在 main.py 中调用时忘记加 await (#54)

* 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)
This commit is contained in:
Helian Nuits
2025-11-25 23:37:13 +08:00
committed by GitHub
parent 5a0731e492
commit 03c35f49d0
22 changed files with 98 additions and 63 deletions
+6 -6
View File
@@ -7,23 +7,23 @@ QQ群日常分析插件
import asyncio import asyncio
from astrbot.api import AstrBotConfig, logger
from astrbot.api.event import filter from astrbot.api.event import filter
from astrbot.api.star import Context, Star 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 ( from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_message_event import (
AiocqhttpMessageEvent, AiocqhttpMessageEvent,
) )
from astrbot.core.message.components import File
from astrbot.core.star.filter.permission import PermissionType from astrbot.core.star.filter.permission import PermissionType
from .src.core.bot_manager import BotManager
# 导入重构后的模块 # 导入重构后的模块
from .src.core.config import ConfigManager from .src.core.config import ConfigManager
from .src.core.bot_manager import BotManager
from .src.reports.generators import ReportGenerator from .src.reports.generators import ReportGenerator
from .src.scheduler.auto_scheduler import AutoScheduler from .src.scheduler.auto_scheduler import AutoScheduler
from .src.utils.pdf_utils import PDFInstaller
from .src.utils.helpers import MessageAnalyzer from .src.utils.helpers import MessageAnalyzer
from .src.utils.pdf_utils import PDFInstaller
# 全局变量 # 全局变量
config_manager = None config_manager = None
@@ -175,7 +175,7 @@ class QQGroupDailyAnalysis(Star):
try: try:
# 获取该群对应的平台ID和bot实例 # 获取该群对应的平台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) bot_instance = bot_manager.get_bot_instance(platform_id)
if not bot_instance: if not bot_instance:
+1 -1
View File
@@ -4,8 +4,8 @@
""" """
from .base_analyzer import BaseAnalyzer from .base_analyzer import BaseAnalyzer
from .golden_quote_analyzer import GoldenQuoteAnalyzer
from .topic_analyzer import TopicAnalyzer from .topic_analyzer import TopicAnalyzer
from .user_title_analyzer import UserTitleAnalyzer from .user_title_analyzer import UserTitleAnalyzer
from .golden_quote_analyzer import GoldenQuoteAnalyzer
__all__ = ["BaseAnalyzer", "TopicAnalyzer", "UserTitleAnalyzer", "GoldenQuoteAnalyzer"] __all__ = ["BaseAnalyzer", "TopicAnalyzer", "UserTitleAnalyzer", "GoldenQuoteAnalyzer"]
+3 -1
View File
@@ -5,13 +5,15 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any from typing import Any
from astrbot.api import logger from astrbot.api import logger
from ...models.data_models import TokenUsage from ...models.data_models import TokenUsage
from ..utils.json_utils import parse_json_response from ..utils.json_utils import parse_json_response
from ..utils.llm_utils import ( from ..utils.llm_utils import (
call_provider_with_retry, call_provider_with_retry,
extract_token_usage,
extract_response_text, extract_response_text,
extract_token_usage,
) )
@@ -4,11 +4,13 @@
""" """
from datetime import datetime from datetime import datetime
from astrbot.api import logger from astrbot.api import logger
from ...models.data_models import GoldenQuote, TokenUsage 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 import InfoUtils
from ..utils.json_utils import extract_golden_quotes_with_regex
from .base_analyzer import BaseAnalyzer
class GoldenQuoteAnalyzer(BaseAnalyzer): class GoldenQuoteAnalyzer(BaseAnalyzer):
+5 -3
View File
@@ -3,13 +3,15 @@
专门处理群聊话题分析 专门处理群聊话题分析
""" """
from datetime import datetime
import re import re
from datetime import datetime
from astrbot.api import logger from astrbot.api import logger
from ...models.data_models import SummaryTopic, TokenUsage 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 import InfoUtils
from ..utils.json_utils import extract_topics_with_regex
from .base_analyzer import BaseAnalyzer
class TopicAnalyzer(BaseAnalyzer): class TopicAnalyzer(BaseAnalyzer):
@@ -4,9 +4,10 @@
""" """
from astrbot.api import logger 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 ..utils.json_utils import extract_user_titles_with_regex
from .base_analyzer import BaseAnalyzer
class UserTitleAnalyzer(BaseAnalyzer): class UserTitleAnalyzer(BaseAnalyzer):
+5 -3
View File
@@ -4,13 +4,15 @@ LLM分析器模块
""" """
import asyncio import asyncio
from astrbot.api import logger 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.topic_analyzer import TopicAnalyzer
from .analyzers.user_title_analyzer import UserTitleAnalyzer 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.json_utils import fix_json
from .utils.llm_utils import call_provider_with_retry
class LLMAnalyzer: class LLMAnalyzer:
+2 -1
View File
@@ -3,8 +3,9 @@
负责用户活跃度分析和其他统计功能 负责用户活跃度分析和其他统计功能
""" """
from datetime import datetime
from collections import defaultdict from collections import defaultdict
from datetime import datetime
from .utils import InfoUtils from .utils import InfoUtils
+5 -7
View File
@@ -3,22 +3,20 @@
包含JSON处理和LLM API请求处理工具 包含JSON处理和LLM API请求处理工具
""" """
from .info_utils import InfoUtils
from .json_utils import ( from .json_utils import (
fix_json, extract_golden_quotes_with_regex,
parse_json_response,
extract_topics_with_regex, extract_topics_with_regex,
extract_user_titles_with_regex, extract_user_titles_with_regex,
extract_golden_quotes_with_regex, fix_json,
parse_json_response,
) )
from .llm_utils import ( from .llm_utils import (
call_provider_with_retry, call_provider_with_retry,
extract_token_usage,
extract_response_text, extract_response_text,
extract_token_usage,
) )
from .info_utils import InfoUtils
__all__ = [ __all__ = [
# JSON处理工具 # JSON处理工具
"fix_json", "fix_json",
+1
View File
@@ -5,6 +5,7 @@ JSON处理工具模块
import json import json
import re import re
from astrbot.api import logger from astrbot.api import logger
+1
View File
@@ -5,6 +5,7 @@ LLM API请求处理工具模块
import asyncio import asyncio
from typing import Any from typing import Any
from astrbot.api import logger from astrbot.api import logger
+27 -13
View File
@@ -4,6 +4,7 @@ Bot实例管理模块
""" """
from typing import Any from typing import Any
from astrbot.api import logger from astrbot.api import logger
@@ -48,19 +49,20 @@ class BotManager:
"""获取指定平台的bot实例,如果不指定则返回第一个可用的实例""" """获取指定平台的bot实例,如果不指定则返回第一个可用的实例"""
if platform_id: if platform_id:
# 如果指定了平台ID,尝试获取 # 如果指定了平台ID,尝试获取
instance = self._bot_instances.get(platform_id) return self._bot_instances.get(platform_id)
if instance:
return instance
# 没有指定平台ID,返回第一个可用的实例 # 没有指定平台ID
if self._bot_instances: if self._bot_instances:
first_platform = list(self._bot_instances.keys())[0] # 如果只有一个实例,直接返回
if len(self._bot_instances) > 1: if len(self._bot_instances) == 1:
logger.debug( return list(self._bot_instances.values())[0]
f"未指定平台,使用第一个可用平台 '{first_platform}' "
f"(共有 {len(self._bot_instances)} 个平台: {list(self._bot_instances.keys())})" # 如果有多个实例,必须指定 platform_id
) logger.error(
return self._bot_instances[first_platform] f"存在多个Bot实例 {list(self._bot_instances.keys())} 但未指定 platform_id"
"无法确定使用哪个实例。请明确指定 platform_id。"
)
return None
# 没有任何平台可用 # 没有任何平台可用
logger.error("没有任何可用的bot实例") logger.error("没有任何可用的bot实例")
@@ -85,14 +87,19 @@ class BotManager:
return self._default_platform return self._default_platform
async def auto_discover_bot_instances(self): async def auto_discover_bot_instances(self):
"""自动发现所有可用的bot实例""" """自动发现所有可用的bot实例 (仅限 QQ/Aiocqhttp)"""
if not self._context or not hasattr(self._context, "platform_manager"): if not self._context or not hasattr(self._context, "platform_manager"):
return {} return {}
platforms = getattr(self._context.platform_manager, "platform_insts", []) # 使用新版 API 获取所有平台实例
platforms = self._context.platform_manager.get_insts()
discovered = {} discovered = {}
for platform in platforms: for platform in platforms:
# 严格过滤:只处理 AiocqhttpAdapter (QQ)
if platform.metadata.name != "aiocqhttp":
continue
# 获取bot实例 # 获取bot实例
bot_client = None bot_client = None
if hasattr(platform, "get_client"): if hasattr(platform, "get_client"):
@@ -138,6 +145,13 @@ class BotManager:
def update_from_event(self, event): def update_from_event(self, event):
"""从事件更新bot实例(用于手动命令)""" """从事件更新bot实例(用于手动命令)"""
# 检查是否为 QQ 平台事件
if (
hasattr(event, "get_platform_name")
and event.get_platform_name() != "aiocqhttp"
):
return False
if hasattr(event, "bot") and event.bot: if hasattr(event, "bot") and event.bot:
# 从事件中获取平台ID # 从事件中获取平台ID
platform_id = None platform_id = None
+2 -1
View File
@@ -4,7 +4,8 @@
""" """
import sys import sys
from astrbot.api import logger, AstrBotConfig
from astrbot.api import AstrBotConfig, logger
class ConfigManager: class ConfigManager:
+4 -2
View File
@@ -3,10 +3,12 @@
负责群聊消息的获取、过滤和预处理 负责群聊消息的获取、过滤和预处理
""" """
from datetime import datetime, timedelta
from collections import defaultdict from collections import defaultdict
from datetime import datetime, timedelta
from astrbot.api import logger 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 from ...src.visualization.activity_charts import ActivityVisualizer
+3 -3
View File
@@ -3,11 +3,11 @@
""" """
from .data_models import ( from .data_models import (
SummaryTopic,
UserTitle,
GoldenQuote, GoldenQuote,
TokenUsage,
GroupStatistics, GroupStatistics,
SummaryTopic,
TokenUsage,
UserTitle,
) )
__all__ = ["SummaryTopic", "UserTitle", "GoldenQuote", "TokenUsage", "GroupStatistics"] __all__ = ["SummaryTopic", "UserTitle", "GoldenQuote", "TokenUsage", "GroupStatistics"]
+9 -5
View File
@@ -3,14 +3,17 @@
负责生成各种格式的分析报告 负责生成各种格式的分析报告
""" """
import asyncio
import base64 import base64
import aiohttp
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
import aiohttp
from astrbot.api import logger from astrbot.api import logger
from .templates import HTMLTemplates
from ..visualization.activity_charts import ActivityVisualizer from ..visualization.activity_charts import ActivityVisualizer
import asyncio from .templates import HTMLTemplates
class ReportGenerator: class ReportGenerator:
@@ -310,10 +313,11 @@ class ReportGenerator:
return False return False
# 动态导入 pyppeteer # 动态导入 pyppeteer
import os
import sys
import pyppeteer import pyppeteer
from pyppeteer import launch from pyppeteer import launch
import sys
import os
# 尝试启动浏览器,如果 Chromium 不存在会自动下载 # 尝试启动浏览器,如果 Chromium 不存在会自动下载
logger.info("启动浏览器进行 PDF 转换") logger.info("启动浏览器进行 PDF 转换")
+3 -1
View File
@@ -4,9 +4,11 @@ HTML模板模块
""" """
import os import os
from astrbot.api import logger
from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2 import Environment, FileSystemLoader, select_autoescape
from astrbot.api import logger
class HTMLTemplates: class HTMLTemplates:
"""HTML模板管理类""" """HTML模板管理类"""
+5 -6
View File
@@ -6,6 +6,7 @@
import asyncio import asyncio
import weakref import weakref
from datetime import datetime, timedelta from datetime import datetime, timedelta
from astrbot.api import logger from astrbot.api import logger
@@ -95,13 +96,11 @@ class AutoScheduler:
) )
continue continue
# 如果所有适配器都尝试失败,记录警告并返回第一个 # 如果所有适配器都尝试失败,记录错误并返回 None
logger.warning( logger.error(
f"⚠️ 无法确定群 {group_id} 属于哪个平台,使用第一个适配器" f" 无法确定群 {group_id} 属于哪个平台 (已尝试: {list(self.bot_manager._bot_instances.keys())})"
) )
first_platform = list(self.bot_manager._bot_instances.keys())[0] return None
logger.warning(f"使用默认平台: {first_platform}")
return first_platform
# 没有任何bot实例,返回None # 没有任何bot实例,返回None
logger.error("❌ 没有注册的bot实例") logger.error("❌ 没有注册的bot实例")
+1 -1
View File
@@ -3,7 +3,7 @@
包含PDF处理和通用工具函数 包含PDF处理和通用工具函数
""" """
from .pdf_utils import PDFInstaller
from .helpers import MessageAnalyzer from .helpers import MessageAnalyzer
from .pdf_utils import PDFInstaller
__all__ = ["PDFInstaller", "MessageAnalyzer"] __all__ = ["PDFInstaller", "MessageAnalyzer"]
+4 -3
View File
@@ -3,11 +3,12 @@
包含消息分析和其他通用功能 包含消息分析和其他通用功能
""" """
from ...src.models.data_models import TokenUsage from astrbot.api import logger
from ...src.core.message_handler import MessageHandler
from ...src.analysis.llm_analyzer import LLMAnalyzer from ...src.analysis.llm_analyzer import LLMAnalyzer
from ...src.analysis.statistics import UserAnalyzer 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: class MessageAnalyzer:
+2 -1
View File
@@ -3,9 +3,10 @@ PDF工具模块
负责PDF相关的安装和管理功能 负责PDF相关的安装和管理功能
""" """
import sys
import asyncio import asyncio
import sys
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from astrbot.api import logger from astrbot.api import logger
+2 -1
View File
@@ -3,8 +3,9 @@
参考 astrbot_plugin_github_analyzer 的实现方式 参考 astrbot_plugin_github_analyzer 的实现方式
""" """
from datetime import datetime
from collections import defaultdict from collections import defaultdict
from datetime import datetime
from ..models.data_models import ActivityVisualization from ..models.data_models import ActivityVisualization