fix: 删除弃用 bot_qq_id 逻辑,定时分析器兼容多平台

This commit is contained in:
SXP-Simon
2026-02-08 22:23:05 +08:00
parent c2701c4447
commit efe1c10a24
4 changed files with 255 additions and 187 deletions
+63 -45
View File
@@ -15,7 +15,7 @@ from ..infrastructure.platform import PlatformAdapter, PlatformAdapterFactory
class BotManager:
"""
Bot实例管理器 - 统一管理所有bot相关操作
与 DDD 架构集成,为每个 bot 实例创建对应的 PlatformAdapter
实现跨平台支持。
"""
@@ -37,7 +37,7 @@ class BotManager:
def set_bot_instance(self, bot_instance, platform_id=None, platform_name=None):
"""
设置bot实例,支持指定平台ID
同时会创建对应的 PlatformAdapter(如果平台被支持)。
"""
if not platform_id:
@@ -45,23 +45,25 @@ class BotManager:
if bot_instance and platform_id:
self._bot_instances[platform_id] = bot_instance
# 为 DDD 集成创建 PlatformAdapter
if platform_name is None:
platform_name = self._detect_platform_name(bot_instance)
if platform_name and PlatformAdapterFactory.is_supported(platform_name):
adapter_config = {
"bot_self_ids": self._bot_self_ids.copy(),
"bot_qq_ids": self._bot_self_ids.copy(), # 兼容旧适配器
"bot_qq_ids": self._bot_self_ids.copy(), # 兼容旧适配器
}
adapter = PlatformAdapterFactory.create(
platform_name, bot_instance, adapter_config
)
if adapter:
self._adapters[platform_id] = adapter
logger.debug(f"已为 {platform_id} ({platform_name}) 创建 PlatformAdapter")
logger.debug(
f"已为 {platform_id} ({platform_name}) 创建 PlatformAdapter"
)
# 自动提取机器人 ID
bot_self_id = self._extract_bot_self_id(bot_instance)
if bot_self_id and bot_self_id not in self._bot_self_ids:
@@ -90,7 +92,7 @@ class BotManager:
# 没有指定平台ID
if not self._bot_instances and self._platforms:
self._refresh_from_stored_platforms()
self._refresh_from_stored_platforms()
if self._bot_instances:
# 如果只有一个实例,直接返回
@@ -113,7 +115,7 @@ class BotManager:
for platform_id, platform in self._platforms.items():
if platform_id in self._bot_instances:
continue
bot_client = None
if hasattr(platform, "get_client"):
bot_client = platform.get_client()
@@ -121,7 +123,7 @@ class BotManager:
bot_client = platform.bot
elif hasattr(platform, "client"):
bot_client = platform.client
if bot_client:
platform_name = None
if hasattr(platform, "metadata"):
@@ -130,9 +132,11 @@ class BotManager:
platform_name = platform.metadata.type
elif hasattr(platform.metadata, "name"):
platform_name = platform.metadata.name
# 后备检测:如果不支持名称
if (not platform_name or not PlatformAdapterFactory.is_supported(str(platform_name))):
if not platform_name or not PlatformAdapterFactory.is_supported(
str(platform_name)
):
detected = self._detect_platform_name(bot_client)
if detected:
platform_name = detected
@@ -169,9 +173,9 @@ class BotManager:
def _detect_platform_name(self, bot_instance) -> Optional[str]:
"""
从 bot 实例检测平台名称,用于创建适配器。
返回平台名称如 'aiocqhttp', 'discord' 等。
检测优先级:
1. bot 实例的 platform 属性
2. 已知的 API 特征检测
@@ -182,18 +186,18 @@ class BotManager:
platform = bot_instance.platform
if isinstance(platform, str):
return platform
# 检查已知的 API 特征(平台无关的方式)
# OneBot/aiocqhttp 特征: 有 call_action 方法
if hasattr(bot_instance, "call_action"):
return "aiocqhttp"
# 使用工厂的已注册平台列表进行类名匹配
class_name = type(bot_instance).__name__.lower()
for platform_name in PlatformAdapterFactory.get_supported_platforms():
if platform_name in class_name:
return platform_name
# 通用类名模式匹配(用于尚未注册的平台)
known_patterns = {
"cqhttp": "aiocqhttp",
@@ -202,7 +206,7 @@ class BotManager:
for pattern, platform in known_patterns.items():
if pattern in class_name:
return platform
return None
# ==================== DDD 集成方法 ====================
@@ -210,22 +214,21 @@ class BotManager:
def get_adapter(self, platform_id: str = None) -> Optional[PlatformAdapter]:
"""
获取指定平台的 PlatformAdapter。
这是 DDD 架构操作的主要方法。
"""
if platform_id:
return self._adapters.get(platform_id)
if self._adapters:
if len(self._adapters) == 1:
return list(self._adapters.values())[0]
logger.error(
f"存在多个适配器 {list(self._adapters.keys())}"
"但未指定 platform_id。"
f"存在多个适配器 {list(self._adapters.keys())}但未指定 platform_id。"
)
return None
return None
def get_all_adapters(self) -> dict:
@@ -248,7 +251,7 @@ class BotManager:
async def auto_discover_bot_instances(self):
"""
自动发现所有可用的bot实例
同时为每个发现的 bot 创建对应的 PlatformAdapter。
"""
if not self._context or not hasattr(self._context, "platform_manager"):
@@ -257,8 +260,10 @@ class BotManager:
# 使用新版 API 获取所有平台实例
platforms = self._context.platform_manager.get_insts()
discovered = {}
logger.info(f"auto_discover_bot_instances: 在管理器中发现 {len(platforms)} 个平台。")
logger.info(
f"auto_discover_bot_instances: 在管理器中发现 {len(platforms)} 个平台。"
)
for p in platforms:
p_id = p.metadata.id if hasattr(p, "metadata") else "unknown"
logger.info(f" - 正在检查平台: {p_id}, 类型: {type(p).__name__}")
@@ -280,7 +285,7 @@ class BotManager:
metadata = platform.meta()
except Exception:
pass
# 检查是否有有效的元数据和ID
platform_id = None
if metadata:
@@ -288,7 +293,7 @@ class BotManager:
platform_id = metadata.id
elif isinstance(metadata, dict):
platform_id = metadata.get("id")
if platform_id:
# 从元数据检测平台名称
platform_name = None
@@ -301,23 +306,30 @@ class BotManager:
platform_name = metadata.name
elif isinstance(metadata, dict) and "name" in metadata:
platform_name = metadata["name"]
# 验证此平台名称是否受支持,如果不支持,尝试从bot实例检测(如果可用)
if (not platform_name or not PlatformAdapterFactory.is_supported(str(platform_name))) and bot_client:
detected = self._detect_platform_name(bot_client)
if detected:
platform_name = detected
logger.debug(f"发现平台: {platform_id} ({platform_name}), 客户端就绪: {bool(bot_client)}")
if (
not platform_name
or not PlatformAdapterFactory.is_supported(str(platform_name))
) and bot_client:
detected = self._detect_platform_name(bot_client)
if detected:
platform_name = detected
logger.debug(
f"发现平台: {platform_id} ({platform_name}), 客户端就绪: {bool(bot_client)}"
)
# 无论bot客户端状态如何,都存储平台实例
self._platforms[platform_id] = platform
if bot_client:
self.set_bot_instance(bot_client, platform_id, platform_name)
discovered[platform_id] = bot_client
else:
logger.info(f"发现平台 {platform_id} 但客户端未就绪。将进行懒加载。")
logger.info(
f"发现平台 {platform_id} 但客户端未就绪。将进行懒加载。"
)
discovered[platform_id] = platform
else:
# 后备方案:如果元数据丢失/损坏但我们有客户端,尝试使用它
@@ -326,8 +338,10 @@ class BotManager:
if platform_name:
# 生成临时ID或使用名称
platform_id = platform_name
logger.warning(f"平台元数据丢失,使用检测到的类型 '{platform_name}' 作为 ID。")
logger.warning(
f"平台元数据丢失,使用检测到的类型 '{platform_name}' 作为 ID。"
)
self._platforms[platform_id] = platform
self.set_bot_instance(bot_client, platform_id, platform_name)
discovered[platform_id] = bot_client
@@ -365,7 +379,7 @@ class BotManager:
"can_analyze": caps.can_analyze(),
"supports_image": caps.supports_image_message,
}
return {
"has_bot_instance": self.has_bot_instance(),
"has_bot_qq_id": self.has_bot_self_id(),
@@ -381,7 +395,7 @@ class BotManager:
"""从事件更新bot实例(用于手动命令)"""
# 检查是否为 QQ 平台事件 (兼容性检查)
# 注意: 非 aiocqhttp 平台也可以使用,只要适配器已注册
if hasattr(event, "bot") and event.bot:
# 从事件中获取平台ID
platform_id = None
@@ -406,10 +420,10 @@ class BotManager:
def _extract_bot_self_id(self, bot_instance):
"""从bot实例中提取自身ID(单个)"""
return self._extract_bot_qq_id(bot_instance)
return self._extract_bot_self_id_impl(bot_instance)
def _extract_bot_qq_id(self, bot_instance):
"""从bot实例中提取QQ号(兼容旧方法名称"""
def _extract_bot_self_id_impl(self, bot_instance):
"""从bot实例中提取ID(通用实现"""
# 尝试多种方式获取bot ID
if hasattr(bot_instance, "self_id") and bot_instance.self_id:
return str(bot_instance.self_id)
@@ -419,6 +433,10 @@ class BotManager:
return str(bot_instance.user_id)
return None
def _extract_bot_qq_id(self, bot_instance):
"""从bot实例中提取QQ号(兼容旧方法名称)"""
return self._extract_bot_self_id_impl(bot_instance)
def validate_for_message_fetching(self, group_id: str) -> bool:
"""验证是否可以进行消息获取"""
return self.has_bot_instance() and bool(group_id)
+10 -21
View File
@@ -20,25 +20,8 @@ class MessageHandler:
self.activity_visualizer = ActivityVisualizer()
self.bot_manager = bot_manager
async def set_bot_qq_ids(self, bot_qq_ids):
"""设置机器人QQ号(支持单个QQ号或QQ号列表"""
try:
if self.bot_manager:
# 确保传入的是列表,保持统一处理
if isinstance(bot_qq_ids, list):
self.bot_manager.set_bot_qq_ids(bot_qq_ids)
elif bot_qq_ids:
self.bot_manager.set_bot_qq_ids([bot_qq_ids])
logger.info(f"设置机器人QQ号: {bot_qq_ids}")
except Exception as e:
logger.error(f"设置机器人QQ号失败: {e}")
def set_bot_manager(self, bot_manager):
"""设置bot管理器"""
self.bot_manager = bot_manager
def _extract_bot_qq_id_from_instance(self, bot_instance):
"""从bot实例中提取QQ号(单个)"""
def _extract_bot_self_id_from_instance(self, bot_instance):
"""从bot实例中提取ID(单个"""
if hasattr(bot_instance, "self_id") and bot_instance.self_id:
return str(bot_instance.self_id)
elif hasattr(bot_instance, "qq") and bot_instance.qq:
@@ -47,6 +30,10 @@ class MessageHandler:
return str(bot_instance.user_id)
return None
def _extract_bot_qq_id_from_instance(self, bot_instance):
"""从bot实例中提取QQ号(已弃用)"""
return self._extract_bot_self_id_from_instance(bot_instance)
async def fetch_group_messages(
self, bot_instance, group_id: str, days: int, platform_id: str = None
) -> list[dict]:
@@ -61,12 +48,14 @@ class MessageHandler:
if self.bot_manager and platform_id:
adapter = self.bot_manager.get_adapter(platform_id)
if adapter:
logger.info(f"使用适配器获取群 {group_id} 消息 (平台: {platform_id})")
logger.info(
f"使用适配器获取群 {group_id} 消息 (平台: {platform_id})"
)
# 使用 adapter 获取统一消息列表
unified_messages = await adapter.fetch_messages(
group_id=str(group_id),
days=days,
max_count=self.config_manager.get_max_messages()
max_count=self.config_manager.get_max_messages(),
)
# 转换为原始格式以兼容后续处理 (后续应迁移到统一格式处理)
return adapter.convert_to_raw_format(unified_messages)
+171 -114
View File
@@ -53,13 +53,17 @@ class AutoScheduler:
"""设置bot实例(保持向后兼容)"""
self.bot_manager.set_bot_instance(bot_instance)
def set_bot_qq_ids(self, bot_qq_ids):
"""设置bot QQ号(支持单个QQ号或QQ号列表)"""
def set_bot_self_ids(self, bot_self_ids):
"""设置bot ID(支持单个ID或ID列表)"""
# 确保传入的是列表,保持统一处理
if isinstance(bot_qq_ids, list):
self.bot_manager.set_bot_qq_ids(bot_qq_ids)
elif bot_qq_ids:
self.bot_manager.set_bot_qq_ids([bot_qq_ids])
if isinstance(bot_self_ids, list):
self.bot_manager.set_bot_self_ids(bot_self_ids)
elif bot_self_ids:
self.bot_manager.set_bot_self_ids([bot_self_ids])
def set_bot_qq_ids(self, bot_qq_ids):
"""设置bot QQ号(已弃用,使用 set_bot_self_ids"""
self.set_bot_self_ids(bot_qq_ids)
async def get_platform_id_for_group(self, group_id):
"""根据群ID获取对应的平台ID"""
@@ -192,30 +196,60 @@ class AutoScheduler:
# 根据配置确定需要分析的群组
group_list_mode = self.config_manager.get_group_list_mode()
# 始终获取所有群组并进行过滤
# 使用 set 存储 (group_id, platform_id) 元组,避免重复
# platform_id 可以为 None (如果是从纯群号配置通过 get_group_list 获取的,或者只是纯群号配置)
# 但为了准确性,我们尽量保留 platform_id
enabled_targets = set()
# 1. 尝试通过 API 获取所有群组 (Discovery)
logger.info(f"自动分析使用 {group_list_mode} 模式,正在获取群列表...")
all_groups = await self._get_all_groups()
logger.info(f"共获取到 {len(all_groups)} 个群组")
enabled_groups = []
for platform_id, group_id in all_groups:
# 构造 UMO 进行检查
umo = f"{platform_id}:GroupMessage:{group_id}"
# 检查 UMO 是否允许 (ConfigManager 会自动处理 UMO 和 Simple ID 的匹配逻辑)
if self.config_manager.is_group_allowed(umo):
enabled_groups.append(group_id)
enabled_targets.add((str(group_id), str(platform_id)))
# 2. 如果是 whitelist 模式,额外检查配置中的 UMO
# 这可以解决 get_group_list 失败 (返回0个群) 但配置了明确 UMO 的情况
if group_list_mode == "whitelist":
whitelist_config = self.config_manager.get_group_list()
logger.info(
f"正在检查白名单配置中的额外 UMO ({len(whitelist_config)} 条)..."
)
for item in whitelist_config:
item = str(item).strip()
# 如果是 UMO 格式 (e.g. lulouch:GroupMessage:123456)
if ":" in item:
parts = item.split(":")
if len(parts) >= 3:
p_id = parts[0]
g_id = parts[-1]
# 检查该平台是否存在
if self.bot_manager.get_bot_instance(p_id):
enabled_targets.add((str(g_id), str(p_id)))
logger.debug(f"添加白名单 UMO 目标: {item}")
else:
logger.warning(
f"白名单 UMO {item} 对应的平台 {p_id} 不存在或未加载"
)
logger.info(
f"根据 {group_list_mode} 过滤后,共有 {len(enabled_groups)} 个群聊需要分析"
f"根据 {group_list_mode} 过滤及合并后,共有 {len(enabled_targets)} 个群聊需要分析"
)
if not enabled_groups:
if not enabled_targets:
logger.info("没有启用的群聊需要分析")
return
logger.info(
f"将为 {len(enabled_groups)} 个群聊并发执行分析: {enabled_groups}"
)
# 转为列表以便索引
target_list = list(enabled_targets) # [(group_id, platform_id), ...]
logger.info(f"将为 {len(target_list)} 个群聊并发执行分析")
# 创建并发任务 - 为每个群聊创建独立的分析任务
# 限制最大并发数
@@ -223,21 +257,21 @@ class AutoScheduler:
logger.info(f"自动分析并发数限制: {max_concurrent}")
sem = asyncio.Semaphore(max_concurrent)
async def safe_perform_analysis(group_id):
async def safe_perform_analysis(gid, pid):
async with sem:
return await self._perform_auto_analysis_for_group_with_timeout(
group_id
gid, pid
)
analysis_tasks = []
for group_id in enabled_groups:
for gid, pid in target_list:
task = asyncio.create_task(
safe_perform_analysis(group_id),
name=f"analysis_group_{group_id}",
safe_perform_analysis(gid, pid),
name=f"analysis_group_{gid}",
)
analysis_tasks.append(task)
# 并发执行所有分析任务,使用 return_exceptions=True 确保单个任务失败不影响其他任务
# 并发执行所有分析任务
results = await asyncio.gather(*analysis_tasks, return_exceptions=True)
# 统计执行结果
@@ -245,41 +279,44 @@ class AutoScheduler:
error_count = 0
for i, result in enumerate(results):
group_id = enabled_groups[i]
gid, _ = target_list[i]
if isinstance(result, Exception):
logger.error(f"{group_id} 分析任务异常: {result}")
logger.error(f"{gid} 分析任务异常: {result}")
error_count += 1
else:
success_count += 1
logger.info(
f"并发分析完成 - 成功: {success_count}, 失败: {error_count}, 总计: {len(enabled_groups)}"
f"并发分析完成 - 成功: {success_count}, 失败: {error_count}, 总计: {len(target_list)}"
)
except Exception as e:
logger.error(f"自动分析执行失败: {e}", exc_info=True)
async def _perform_auto_analysis_for_group_with_timeout(self, group_id: str):
async def _perform_auto_analysis_for_group_with_timeout(
self, group_id: str, target_platform_id: str = None
):
"""为指定群执行自动分析(带超时控制)"""
try:
# 为每个群聊设置独立的超时时间(20分钟)- 使用 asyncio.wait_for 兼容所有 Python 版本
# 为每个群聊设置独立的超时时间(20分钟)
await asyncio.wait_for(
self._perform_auto_analysis_for_group(group_id), timeout=1200
self._perform_auto_analysis_for_group(group_id, target_platform_id),
timeout=1200,
)
except asyncio.TimeoutError:
logger.error(f"{group_id} 分析超时(20分钟),跳过该群分析")
except Exception as e:
logger.error(f"{group_id} 分析任务执行失败: {e}")
async def _perform_auto_analysis_for_group(self, group_id: str):
async def _perform_auto_analysis_for_group(
self, group_id: str, target_platform_id: str = None
):
"""为指定群执行自动分析(核心逻辑)"""
# 为每个群聊使用独立的锁,避免全局锁导致串行化
# 为每个群聊使用独立的锁
group_lock_key = f"analysis_{group_id}"
if not hasattr(self, "_group_locks"):
self._group_locks = weakref.WeakValueDictionary()
# 从 WeakValueDictionary 获取锁,如果不存在则创建
# 注意:必须将锁赋值给局部变量以保持引用,否则可能会被回收
lock = self._group_locks.get(group_lock_key)
if lock is None:
lock = asyncio.Lock()
@@ -293,14 +330,12 @@ class AutoScheduler:
trace_id = TraceContext.generate(prefix=f"group_{group_id}")
TraceContext.set(trace_id)
# 获取当前日期和时间槽 (HH-MM)
import datetime
now = datetime.datetime.now()
date_str = now.strftime("%Y-%m-%d")
time_str = now.strftime("%H-%M")
# 检查是否已有该时间段分析记录
if await self.history_manager.has_history(group_id, date_str, time_str):
logger.info(
f"{group_id}{date_str} {time_str} 已有分析记录,跳过自动分析"
@@ -309,7 +344,6 @@ class AutoScheduler:
logger.info(f"开始为群 {group_id} 执行自动分析(并发任务)")
# 检查bot管理器状态
if not self.bot_manager.is_ready_for_auto_analysis():
status = self.bot_manager.get_status_info()
logger.warning(
@@ -317,104 +351,126 @@ class AutoScheduler:
)
return
logger.info(f"开始为群 {group_id} 执行自动分析(并发任务)")
# 获取所有可用的平台,依次尝试获取消息
messages = None
platform_id = None
bot_instance = None
# 获取所有可用的平台ID和bot实例
if (
hasattr(self.bot_manager, "_bot_instances")
and self.bot_manager._bot_instances
):
available_platforms = list(self.bot_manager._bot_instances.items())
logger.info(
f"{group_id} 检测到 {len(available_platforms)} 个可用平台,开始依次尝试..."
)
for test_platform_id, test_bot_instance in available_platforms:
# 检查该平台是否启用了此插件
if not self.bot_manager.is_plugin_enabled(
test_platform_id, "astrbot_plugin_qq_group_daily_analysis"
):
logger.debug(f"平台 {test_platform_id} 未启用此插件,跳过")
continue
# 1. 优先使用指定的 platform_id (如果有)
if target_platform_id:
if self.bot_manager.is_plugin_enabled(
target_platform_id, "astrbot_plugin_qq_group_daily_analysis"
):
try:
logger.info(
f"尝试使用平台 {test_platform_id} 获取群 {group_id} 的消息..."
f"使用指定平台 {target_platform_id} 获取群 {group_id} 的消息..."
)
analysis_days = self.config_manager.get_analysis_days()
test_messages = (
await self.message_handler.fetch_group_messages(
test_bot_instance,
group_id,
analysis_days,
test_platform_id,
)
bot_instance = self.bot_manager.get_bot_instance(
target_platform_id
)
if test_messages and len(test_messages) > 0:
# 成功获取到消息,使用这个平台
messages = test_messages
platform_id = test_platform_id
bot_instance = test_bot_instance
logger.info(
f"✅ 群 {group_id} 成功通过平台 {platform_id} 获取到 {len(messages)} 条消息"
)
break
else:
logger.debug(
f"平台 {test_platform_id} 未获取到消息,继续尝试下一个平台"
if bot_instance:
analysis_days = self.config_manager.get_analysis_days()
messages = (
await self.message_handler.fetch_group_messages(
bot_instance,
group_id,
analysis_days,
target_platform_id,
)
)
if messages:
platform_id = target_platform_id
logger.info(
f"✅ 群 {group_id} 成功通过平台 {platform_id} 获取到 {len(messages)} 条消息"
)
except Exception as e:
logger.debug(
f"平台 {test_platform_id} 获取消息失败: {e},继续尝试下一个平台"
logger.error(
f"指定平台 {target_platform_id} 获取消息失败: {e}"
)
continue
if not messages:
logger.warning(
f"{group_id} 所有平台都尝试失败,未获取到足够的消息记录"
# 2. 如果指定平台失败或没有指定,尝试自动检测 (原有逻辑)
if not messages:
# 获取所有可用的平台ID和bot实例
if (
hasattr(self.bot_manager, "_bot_instances")
and self.bot_manager._bot_instances
):
available_platforms = list(
self.bot_manager._bot_instances.items()
)
return
else:
# 回退到原来的逻辑(单个平台)
logger.warning(f"{group_id} 没有多个平台可用,使用回退逻辑")
platform_id = await self.get_platform_id_for_group(group_id)
if not platform_id:
logger.error(f"❌ 群 {group_id} 无法获取平台ID,跳过分析")
return
bot_instance = self.bot_manager.get_bot_instance(platform_id)
if not bot_instance:
logger.error(
f"❌ 群 {group_id} 未找到对应的bot实例(平台: {platform_id}"
logger.info(
f"{group_id} 检测到 {len(available_platforms)} 个可用平台,开始依次尝试..."
)
return
# 获取群聊消息
analysis_days = self.config_manager.get_analysis_days()
messages = await self.message_handler.fetch_group_messages(
bot_instance, group_id, analysis_days, platform_id
)
for test_platform_id, test_bot_instance in available_platforms:
# 如果已经试过 target_platform_id,跳过
if (
target_platform_id
and test_platform_id == target_platform_id
):
continue
if messages is None:
logger.warning(f"{group_id} 获取消息失败,跳过分析")
return
elif not messages:
logger.warning(f"{group_id} 未获取到足够的消息记录")
return
# 检查该平台是否启用了此插件
if not self.bot_manager.is_plugin_enabled(
test_platform_id,
"astrbot_plugin_qq_group_daily_analysis",
):
logger.debug(
f"平台 {test_platform_id} 未启用此插件,跳过"
)
continue
try:
logger.info(
f"尝试使用平台 {test_platform_id} 获取群 {group_id} 的消息..."
)
analysis_days = self.config_manager.get_analysis_days()
test_messages = (
await self.message_handler.fetch_group_messages(
test_bot_instance,
group_id,
analysis_days,
test_platform_id,
)
)
if test_messages and len(test_messages) > 0:
# 成功获取到消息,使用这个平台
messages = test_messages
platform_id = test_platform_id
bot_instance = test_bot_instance
logger.info(
f"✅ 群 {group_id} 成功通过平台 {platform_id} 获取到 {len(messages)} 条消息"
)
break
else:
logger.debug(
f"平台 {test_platform_id} 未获取到消息,继续尝试下一个平台"
)
except Exception as e:
logger.debug(
f"平台 {test_platform_id} 获取消息失败: {e},继续尝试下一个平台"
)
continue
if not messages:
logger.warning(
f"{group_id} 所有平台都尝试失败,未获取到足够的消息记录"
)
return
else:
# 回退到原来的逻辑(单个平台)- 几乎不会走到这里,除非 _bot_instances 为空
pass # 省略 legacy 逻辑,因为 _bot_instances 为空在上面 is_ready 检查了
if not messages:
# 最后尝试 legacy get_platform_id_for_group
# ... (Keep existing fallback if needed, but the loop above covers most cases)
pass
# 检查消息数量
min_threshold = self.config_manager.get_min_messages_threshold()
if len(messages) < min_threshold:
if not messages or len(messages) < min_threshold:
logger.warning(
f"{group_id} 消息数量不足({len(messages)}条),跳过分析"
f"{group_id} 消息数量不足({len(messages) if messages else 0}条),跳过分析"
)
return
@@ -431,7 +487,6 @@ class AutoScheduler:
return
# 生成并发送报告
# await self._send_analysis_report(group_id, analysis_result, platform_id)
await self.report_dispatcher.dispatch(
group_id, analysis_result, platform_id
)
@@ -488,7 +543,9 @@ class AutoScheduler:
adapter = PlatformAdapterFactory.create(
platform_name,
bot_instance,
config={"bot_qq_ids": self.config_manager.get_bot_qq_ids()},
config={
"bot_self_ids": self.config_manager.get_bot_self_ids(),
},
)
# 3. 如果适配器创建成功,使用通用接口获取群列表
+11 -7
View File
@@ -24,8 +24,8 @@ class MessageAnalyzer:
self.llm_analyzer = LLMAnalyzer(context, config_manager)
self.user_analyzer = UserAnalyzer(config_manager)
def _extract_bot_qq_id_from_instance(self, bot_instance):
"""从bot实例中提取QQ号(单个)"""
def _extract_bot_self_id_from_instance(self, bot_instance):
"""从bot实例中提取ID(单个)"""
if hasattr(bot_instance, "self_id") and bot_instance.self_id:
return str(bot_instance.self_id)
elif hasattr(bot_instance, "qq") and bot_instance.qq:
@@ -34,16 +34,20 @@ class MessageAnalyzer:
return str(bot_instance.user_id)
return None
def _extract_bot_qq_id_from_instance(self, bot_instance):
"""从bot实例中提取QQ号(已弃用)"""
return self._extract_bot_self_id_from_instance(bot_instance)
async def set_bot_instance(self, bot_instance, platform_id=None):
"""设置bot实例(保持向后兼容)"""
if self.bot_manager:
self.bot_manager.set_bot_instance(bot_instance, platform_id)
else:
# 从bot实例提取QQ号并设置为列表
bot_qq_id = self._extract_bot_qq_id_from_instance(bot_instance)
if bot_qq_id:
# 将单个QQ号转换为列表,保持统一处理
await self.message_handler.set_bot_qq_ids([bot_qq_id])
# 从bot实例提取ID并设置为列表
bot_self_id = self._extract_bot_self_id_from_instance(bot_instance)
if bot_self_id:
# 将单个ID转换为列表,保持统一处理
await self.message_handler.set_bot_self_ids([bot_self_id])
async def analyze_messages(
self, messages: list[dict], group_id: str, unified_msg_origin: str = None