From 42088670b3a078e79078b61cda5939c68f6a1239 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 5 Sep 2025 17:51:11 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(memory):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E5=AF=B9=E8=B1=A1=E6=9B=BF=E4=BB=A3=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=88=A4=E6=96=AD=E6=9D=A5=E5=A4=84=E7=90=86=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=86=85=E5=AD=98=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过引入一个`MockHippocampusManager`类,当内存系统在配置中被禁用时,它将提供一个与真实管理器接口相同的模拟对象。这消除了在代码中散布的多个`if global_config.memory.enable_memory:`条件检查。 这种重构简化了`MainSystem`类中的初始化和任务调度逻辑,使得代码更加清晰和易于维护,因为现在可以无条件地调用内存系统的方法,而不用担心它是否被启用。 --- src/main.py | 93 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/src/main.py b/src/main.py index 10ae224db..00d430cc5 100644 --- a/src/main.py +++ b/src/main.py @@ -28,12 +28,36 @@ from src.plugin_system.core.plugin_hot_reload import hot_reload_manager # 导入消息API和traceback模块 from src.common.message import get_global_api - -# 条件导入记忆系统 -if global_config.memory.enable_memory: - from src.chat.memory_system.Hippocampus import hippocampus_manager - -# 插件系统现在使用统一的插件加载器 + +from src.chat.memory_system.Hippocampus import hippocampus_manager +if not global_config.memory.enable_memory: + import src.chat.memory_system.Hippocampus as hippocampus_module + + class MockHippocampusManager: + def initialize(self): + pass + def get_hippocampus(self): + return None + async def build_memory(self): + pass + async def forget_memory(self, percentage: float = 0.005): + pass + async def consolidate_memory(self): + pass + async def get_memory_from_text(self, text: str, max_memory_num: int = 3, max_memory_length: int = 2, max_depth: int = 3, fast_retrieval: bool = False) -> list: + return [] + async def get_memory_from_topic(self, valid_keywords: list[str], max_memory_num: int = 3, max_memory_length: int = 2, max_depth: int = 3) -> list: + return [] + async def get_activate_from_text(self, text: str, max_depth: int = 3, fast_retrieval: bool = False) -> tuple[float, list[str]]: + return 0.0, [] + def get_memory_from_keyword(self, keyword: str, max_depth: int = 2) -> list: + return [] + def get_all_node_names(self) -> list: + return [] + + hippocampus_module.hippocampus_manager = MockHippocampusManager() + + # 插件系统现在使用统一的插件加载器 install(extra_lines=3) @@ -42,12 +66,8 @@ logger = get_logger("main") class MainSystem: def __init__(self): - # 根据配置条件性地初始化记忆系统 - if global_config.memory.enable_memory: - self.hippocampus_manager = hippocampus_manager - else: - self.hippocampus_manager = None - + self.hippocampus_manager = hippocampus_manager + self.individuality: Individuality = get_individuality() # 使用消息API替代直接的FastAPI实例 @@ -201,22 +221,18 @@ MoFox_Bot(第三方修改版) logger.info("聊天管理器初始化成功") - # 根据配置条件性地初始化记忆系统 - if global_config.memory.enable_memory: - if self.hippocampus_manager: - self.hippocampus_manager.initialize() - logger.info("记忆系统初始化成功") - - # 初始化异步记忆管理器 - try: - from src.chat.memory_system.async_memory_optimizer import async_memory_manager - - await async_memory_manager.initialize() - logger.info("记忆管理器初始化成功") - except Exception as e: - logger.error(f"记忆管理器初始化失败: {e}") - else: - logger.info("记忆系统已禁用,跳过初始化") + # 初始化记忆系统 + self.hippocampus_manager.initialize() + logger.info("记忆系统初始化成功") + + # 初始化异步记忆管理器 + try: + from src.chat.memory_system.async_memory_optimizer import async_memory_manager + + await async_memory_manager.initialize() + logger.info("记忆管理器初始化成功") + except Exception as e: + logger.error(f"记忆管理器初始化失败: {e}") # await asyncio.sleep(0.5) #防止logger输出飞了 @@ -265,15 +281,14 @@ MoFox_Bot(第三方修改版) self.server.run(), ] - # 根据配置条件性地添加记忆系统相关任务 - if global_config.memory.enable_memory and self.hippocampus_manager: - tasks.extend( - [ - self.build_memory_task(), - self.forget_memory_task(), - self.consolidate_memory_task(), - ] - ) + # 添加记忆系统相关任务 + tasks.extend( + [ + self.build_memory_task(), + self.forget_memory_task(), + self.consolidate_memory_task(), + ] + ) await asyncio.gather(*tasks) @@ -305,10 +320,6 @@ MoFox_Bot(第三方修改版) def sync_build_memory(): """在线程池中执行同步记忆构建""" - if not self.hippocampus_manager: - logger.error("尝试在禁用记忆系统时构建记忆,操作已取消。") - return - try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) From 57e5244b1f87e208c48bb779a44b2b59a0fd2c7c Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 5 Sep 2025 17:52:27 +0800 Subject: [PATCH 2/5] =?UTF-8?q?refactor(main):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=A4=9A=E4=BD=99=E7=9A=84ImportError=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.py b/src/main.py index 00d430cc5..96d5b8322 100644 --- a/src/main.py +++ b/src/main.py @@ -123,8 +123,6 @@ class MainSystem: else: loop.run_until_complete(async_memory_manager.shutdown()) logger.info("🛑 记忆管理器已停止") - except ImportError: - pass # 异步记忆优化器不存在 except Exception as e: logger.error(f"停止记忆管理器时出错: {e}") From 420a7f0bef40b8119013ec9de57e05141366ae66 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 5 Sep 2025 18:36:49 +0800 Subject: [PATCH 3/5] =?UTF-8?q?refactor(chat):=20=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 `send_response` 方法中多余的 `reply_to_str` 参数 - 调整 `text_to_stream` 调用,不再传递消息数据作为回复目标 - 确保 `handle_message_storage` 的 `reason` 参数始终为字符串 --- src/chat/chat_loop/response_handler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chat/chat_loop/response_handler.py b/src/chat/chat_loop/response_handler.py index ecfc6addb..63d23ef62 100644 --- a/src/chat/chat_loop/response_handler.py +++ b/src/chat/chat_loop/response_handler.py @@ -64,7 +64,7 @@ class ResponseHandler: - 构建并返回完整的循环信息 - 用于上级方法的状态跟踪 """ - reply_text = await self.send_response(response_set, reply_to_str, loop_start_time, action_message) + reply_text = await self.send_response(response_set, loop_start_time, action_message) person_info_manager = get_person_info_manager() @@ -166,8 +166,8 @@ class ResponseHandler: await send_api.text_to_stream( text=data, stream_id=self.context.stream_id, - reply_to_message = message_data, - set_reply=need_reply, + reply_to_message=None, + set_reply=False, typing=True, ) @@ -209,7 +209,7 @@ class ResponseHandler: ) # 根据反注入结果处理消息数据 - await anti_injector.handle_message_storage(result, modified_content, reason, message_data) + await anti_injector.handle_message_storage(result, modified_content, reason or "", message_data) if result == ProcessResult.BLOCKED_BAN: # 用户被封禁 - 直接阻止回复生成 From 5bae2fa8f8286a768710a33059b39d0808ea3548 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 5 Sep 2025 19:11:21 +0800 Subject: [PATCH 4/5] =?UTF-8?q?refactor(chat):=20=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E5=8C=96=E8=B7=A8=E7=BE=A4=E8=81=8A=E4=B8=8A=E4=B8=8B=E6=96=87?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 `build_cross_context` 方法的实现委托给 `cross_context_api`。 这简化了 `prompt_utils` 中的代码,将复杂的上下文构建逻辑(包括获取其他群聊、根据模式获取和格式化消息)封装到专用的API中,提高了代码的模块化和可维护性。 --- src/chat/utils/prompt_utils.py | 128 +++----------------- src/plugin_system/apis/cross_context_api.py | 118 ++++++++++++++++++ 2 files changed, 138 insertions(+), 108 deletions(-) create mode 100644 src/plugin_system/apis/cross_context_api.py diff --git a/src/chat/utils/prompt_utils.py b/src/chat/utils/prompt_utils.py index f9985be53..4f9e36777 100644 --- a/src/chat/utils/prompt_utils.py +++ b/src/chat/utils/prompt_utils.py @@ -9,13 +9,9 @@ from typing import Dict, Any, Optional, Tuple from src.common.logger import get_logger from src.config.config import global_config -from src.chat.utils.chat_message_builder import ( - get_raw_msg_before_timestamp_with_chat, - build_readable_messages_with_id, -) from src.chat.message_receive.chat_stream import get_chat_manager from src.person_info.person_info import get_person_info_manager - +from src.plugin_system.apis import cross_context_api logger = get_logger("prompt_utils") @@ -84,113 +80,29 @@ class PromptUtils: @staticmethod async def build_cross_context( - chat_id: str, target_user_info: Optional[Dict[str, Any]], current_prompt_mode: str - ) -> str: - """ - 构建跨群聊上下文 - 统一实现,完全继承DefaultReplyer功能 + chat_id: str, target_user_info: Optional[Dict[str, Any]], current_prompt_mode: str + ) -> str: + """ + 构建跨群聊上下文 - 统一实现,完全继承DefaultReplyer功能 + """ + if not global_config.cross_context.enable: + return "" - Args: - chat_id: 当前聊天ID - target_user_info: 目标用户信息 - current_prompt_mode: 当前提示模式 + other_chat_raw_ids = cross_context_api.get_context_groups(chat_id) + if not other_chat_raw_ids: + return "" + + chat_stream = get_chat_manager().get_stream(chat_id) + if not chat_stream: + return "" + + if current_prompt_mode == "normal": + return await cross_context_api.build_cross_context_normal(chat_stream, other_chat_raw_ids) + elif current_prompt_mode == "s4u": + return await cross_context_api.build_cross_context_s4u(chat_stream, other_chat_raw_ids, target_user_info) - Returns: - str: 跨群上下文块 - """ - if not global_config.cross_context.enable: return "" - # 找到当前群聊所在的共享组 - target_group = None - current_stream = get_chat_manager().get_stream(chat_id) - if not current_stream or not current_stream.group_info: - return "" - - try: - current_chat_raw_id = current_stream.group_info.group_id - except Exception as e: - logger.error(f"获取群聊ID失败: {e}") - return "" - - for group in global_config.cross_context.groups: - if str(current_chat_raw_id) in group.chat_ids: - target_group = group - break - - if not target_group: - return "" - - # 根据prompt_mode选择策略 - other_chat_raw_ids = [chat_id for chat_id in target_group.chat_ids if chat_id != str(current_chat_raw_id)] - - cross_context_messages = [] - - if current_prompt_mode == "normal": - # normal模式:获取其他群聊的最近N条消息 - for chat_raw_id in other_chat_raw_ids: - stream_id = get_chat_manager().get_stream_id(current_stream.platform, chat_raw_id, is_group=True) - if not stream_id: - continue - - try: - messages = get_raw_msg_before_timestamp_with_chat( - chat_id=stream_id, - timestamp=time.time(), - limit=5, # 可配置 - ) - if messages: - chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id - formatted_messages, _ = build_readable_messages_with_id(messages, timestamp_mode="relative") - cross_context_messages.append(f'[以下是来自"{chat_name}"的近期消息]\n{formatted_messages}') - except Exception as e: - logger.error(f"获取群聊{chat_raw_id}的消息失败: {e}") - continue - - elif current_prompt_mode == "s4u": - # s4u模式:获取当前发言用户在其他群聊的消息 - if target_user_info: - user_id = target_user_info.get("user_id") - - if user_id: - for chat_raw_id in other_chat_raw_ids: - stream_id = get_chat_manager().get_stream_id( - current_stream.platform, chat_raw_id, is_group=True - ) - if not stream_id: - continue - - try: - messages = get_raw_msg_before_timestamp_with_chat( - chat_id=stream_id, - timestamp=time.time(), - limit=20, # 获取更多消息以供筛选 - ) - user_messages = [msg for msg in messages if msg.get("user_id") == user_id][ - -5: - ] # 筛选并取最近5条 - - if user_messages: - chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id - user_name = ( - target_user_info.get("person_name") - or target_user_info.get("user_nickname") - or user_id - ) - formatted_messages, _ = build_readable_messages_with_id( - user_messages, timestamp_mode="relative" - ) - cross_context_messages.append( - f'[以下是"{user_name}"在"{chat_name}"的近期发言]\n{formatted_messages}' - ) - except Exception as e: - logger.error(f"获取用户{user_id}在群聊{chat_raw_id}的消息失败: {e}") - continue - - if not cross_context_messages: - return "" - - return "# 跨群上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" - @staticmethod def parse_reply_target_id(reply_to: str) -> str: """ diff --git a/src/plugin_system/apis/cross_context_api.py b/src/plugin_system/apis/cross_context_api.py new file mode 100644 index 000000000..f926742aa --- /dev/null +++ b/src/plugin_system/apis/cross_context_api.py @@ -0,0 +1,118 @@ +""" +跨群聊上下文API +""" + +import time +from typing import Dict, Any, Optional, List + +from src.common.logger import get_logger +from src.config.config import global_config +from src.chat.utils.chat_message_builder import ( + get_raw_msg_before_timestamp_with_chat, + build_readable_messages_with_id, +) +from src.chat.message_receive.chat_stream import get_chat_manager, ChatStream + +logger = get_logger("cross_context_api") + + +def get_context_groups(chat_id: str) -> Optional[List[str]]: + """ + 获取当前群聊所在的共享组的其他群聊ID + """ + current_stream = get_chat_manager().get_stream(chat_id) + if not current_stream or not current_stream.group_info: + return None + + try: + current_chat_raw_id = current_stream.group_info.group_id + except Exception as e: + logger.error(f"获取群聊ID失败: {e}") + return None + + for group in global_config.cross_context.groups: + if str(current_chat_raw_id) in group.chat_ids: + return [chat_id for chat_id in group.chat_ids if chat_id != str(current_chat_raw_id)] + + return None + + +async def build_cross_context_normal(chat_stream: ChatStream, other_chat_raw_ids: List[str]) -> str: + """ + 构建跨群聊上下文 (Normal模式) + """ + cross_context_messages = [] + for chat_raw_id in other_chat_raw_ids: + stream_id = get_chat_manager().get_stream_id(chat_stream.platform, chat_raw_id, is_group=True) + if not stream_id: + continue + + try: + messages = get_raw_msg_before_timestamp_with_chat( + chat_id=stream_id, + timestamp=time.time(), + limit=5, # 可配置 + ) + if messages: + chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id + formatted_messages, _ = build_readable_messages_with_id(messages, timestamp_mode="relative") + cross_context_messages.append(f'[以下是来自"{chat_name}"的近期消息]\n{formatted_messages}') + except Exception as e: + logger.error(f"获取群聊{chat_raw_id}的消息失败: {e}") + continue + + if not cross_context_messages: + return "" + + return "# 跨群上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" + + +async def build_cross_context_s4u( + chat_stream: ChatStream, other_chat_raw_ids: List[str], target_user_info: Optional[Dict[str, Any]] +) -> str: + """ + 构建跨群聊上下文 (S4U模式) + """ + cross_context_messages = [] + if target_user_info: + user_id = target_user_info.get("user_id") + + if user_id: + for chat_raw_id in other_chat_raw_ids: + stream_id = get_chat_manager().get_stream_id( + chat_stream.platform, chat_raw_id, is_group=True + ) + if not stream_id: + continue + + try: + messages = get_raw_msg_before_timestamp_with_chat( + chat_id=stream_id, + timestamp=time.time(), + limit=20, # 获取更多消息以供筛选 + ) + user_messages = [msg for msg in messages if msg.get("user_id") == user_id][ + -5: + ] # 筛选并取最近5条 + + if user_messages: + chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id + user_name = ( + target_user_info.get("person_name") + or target_user_info.get("user_nickname") + or user_id + ) + formatted_messages, _ = build_readable_messages_with_id( + user_messages, timestamp_mode="relative" + ) + cross_context_messages.append( + f'[以下是"{user_name}"在"{chat_name}"的近期发言]\n{formatted_messages}' + ) + except Exception as e: + logger.error(f"获取用户{user_id}在群聊{chat_raw_id}的消息失败: {e}") + continue + + if not cross_context_messages: + return "" + + return "# 跨群上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" \ No newline at end of file From e3d1209d145920e65a4ed15f854f5eab1d2d44d5 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 5 Sep 2025 19:30:06 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat(cross=5Fcontext):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=A7=81=E8=81=8A=E5=92=8C=E7=BE=A4=E8=81=8A=E6=B7=B7=E5=90=88?= =?UTF-8?q?=E7=9A=84=E4=B8=8A=E4=B8=8B=E6=96=87=E5=85=B1=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次更新扩展了跨上下文共享功能,使其不再局限于群聊之间,现在可以支持群聊与私聊的混合共享。 主要变更: - 将 `cross_context.groups` 的 `chat_ids` 配置格式从一维字符串列表(仅群号)更新为二维列表 `[["type", "id"], ...]`,其中 `type` 可以是 "group" 或 "private"。 - 更新了 `cross_context_api` 以正确处理新的配置格式,使其能够识别并获取私聊和群聊的消息历史。 - 相应地更新了配置文件模板 `bot_config_template.toml` 以反映新的配置格式和功能。 BREAKING CHANGE: `cross_context.groups` 的 `chat_ids` 配置格式已更改。旧的一维群号列表格式不再受支持,用户需要按照 `[["type", "id"], ...]` 的新格式更新其配置文件才能使用此功能。 --- src/config/official_configs.py | 4 +- src/plugin_system/apis/cross_context_api.py | 70 ++++++++++++--------- template/bot_config_template.toml | 19 +++--- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 67c2d4b6b..54a138d0b 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -652,7 +652,9 @@ class ContextGroup(ValidatedConfigBase): """上下文共享组配置""" name: str = Field(..., description="共享组的名称") - chat_ids: List[str] = Field(..., description="属于该组的聊天ID列表") + chat_ids: List[List[str]] = Field( + ..., description='属于该组的聊天ID列表,格式为 [["type", "chat_id"], ...],例如 [["group", "123456"], ["private", "789012"]]' + ) class CrossContextConfig(ValidatedConfigBase): diff --git a/src/plugin_system/apis/cross_context_api.py b/src/plugin_system/apis/cross_context_api.py index f926742aa..5a0b896df 100644 --- a/src/plugin_system/apis/cross_context_api.py +++ b/src/plugin_system/apis/cross_context_api.py @@ -16,34 +16,45 @@ from src.chat.message_receive.chat_stream import get_chat_manager, ChatStream logger = get_logger("cross_context_api") -def get_context_groups(chat_id: str) -> Optional[List[str]]: +def get_context_groups(chat_id: str) -> Optional[List[List[str]]]: """ - 获取当前群聊所在的共享组的其他群聊ID + 获取当前聊天所在的共享组的其他聊天ID """ current_stream = get_chat_manager().get_stream(chat_id) - if not current_stream or not current_stream.group_info: + if not current_stream: return None - try: - current_chat_raw_id = current_stream.group_info.group_id - except Exception as e: - logger.error(f"获取群聊ID失败: {e}") - return None + is_group = current_stream.group_info is not None + current_chat_raw_id = ( + current_stream.group_info.group_id if is_group else current_stream.user_info.user_id + ) + current_type = "group" if is_group else "private" for group in global_config.cross_context.groups: - if str(current_chat_raw_id) in group.chat_ids: - return [chat_id for chat_id in group.chat_ids if chat_id != str(current_chat_raw_id)] + # 检查当前聊天的ID和类型是否在组的chat_ids中 + if [current_type, str(current_chat_raw_id)] in group.chat_ids: + # 返回组内其他聊天的 [type, id] 列表 + return [ + chat_info + for chat_info in group.chat_ids + if chat_info != [current_type, str(current_chat_raw_id)] + ] return None -async def build_cross_context_normal(chat_stream: ChatStream, other_chat_raw_ids: List[str]) -> str: +async def build_cross_context_normal( + chat_stream: ChatStream, other_chat_infos: List[List[str]] +) -> str: """ - 构建跨群聊上下文 (Normal模式) + 构建跨群聊/私聊上下文 (Normal模式) """ cross_context_messages = [] - for chat_raw_id in other_chat_raw_ids: - stream_id = get_chat_manager().get_stream_id(chat_stream.platform, chat_raw_id, is_group=True) + for chat_type, chat_raw_id in other_chat_infos: + is_group = chat_type == "group" + stream_id = get_chat_manager().get_stream_id( + chat_stream.platform, chat_raw_id, is_group=is_group + ) if not stream_id: continue @@ -54,33 +65,38 @@ async def build_cross_context_normal(chat_stream: ChatStream, other_chat_raw_ids limit=5, # 可配置 ) if messages: - chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id - formatted_messages, _ = build_readable_messages_with_id(messages, timestamp_mode="relative") + chat_name = get_chat_manager().get_stream_name(stream_id) or chat_raw_id + formatted_messages, _ = build_readable_messages_with_id( + messages, timestamp_mode="relative" + ) cross_context_messages.append(f'[以下是来自"{chat_name}"的近期消息]\n{formatted_messages}') except Exception as e: - logger.error(f"获取群聊{chat_raw_id}的消息失败: {e}") + logger.error(f"获取聊天 {chat_raw_id} 的消息失败: {e}") continue if not cross_context_messages: return "" - return "# 跨群上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" + return "# 跨上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" async def build_cross_context_s4u( - chat_stream: ChatStream, other_chat_raw_ids: List[str], target_user_info: Optional[Dict[str, Any]] + chat_stream: ChatStream, + other_chat_infos: List[List[str]], + target_user_info: Optional[Dict[str, Any]], ) -> str: """ - 构建跨群聊上下文 (S4U模式) + 构建跨群聊/私聊上下文 (S4U模式) """ cross_context_messages = [] if target_user_info: user_id = target_user_info.get("user_id") if user_id: - for chat_raw_id in other_chat_raw_ids: + for chat_type, chat_raw_id in other_chat_infos: + is_group = chat_type == "group" stream_id = get_chat_manager().get_stream_id( - chat_stream.platform, chat_raw_id, is_group=True + chat_stream.platform, chat_raw_id, is_group=is_group ) if not stream_id: continue @@ -91,12 +107,10 @@ async def build_cross_context_s4u( timestamp=time.time(), limit=20, # 获取更多消息以供筛选 ) - user_messages = [msg for msg in messages if msg.get("user_id") == user_id][ - -5: - ] # 筛选并取最近5条 + user_messages = [msg for msg in messages if msg.get("user_id") == user_id][-5:] if user_messages: - chat_name = get_chat_manager().get_stream_name(stream_id) or stream_id + chat_name = get_chat_manager().get_stream_name(stream_id) or chat_raw_id user_name = ( target_user_info.get("person_name") or target_user_info.get("user_nickname") @@ -109,10 +123,10 @@ async def build_cross_context_s4u( f'[以下是"{user_name}"在"{chat_name}"的近期发言]\n{formatted_messages}' ) except Exception as e: - logger.error(f"获取用户{user_id}在群聊{chat_raw_id}的消息失败: {e}") + logger.error(f"获取用户 {user_id} 在聊天 {chat_raw_id} 的消息失败: {e}") continue if not cross_context_messages: return "" - return "# 跨群上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" \ No newline at end of file + return "# 跨上下文参考\n" + "\n\n".join(cross_context_messages) + "\n" \ No newline at end of file diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 196ff5ff7..e7221cf7c 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -473,19 +473,20 @@ pre_sleep_notification_groups = [] # 用于生成睡前消息的提示。AI会根据这个提示生成一句晚安问候。 pre_sleep_prompt = "我准备睡觉了,请生成一句简短自然的晚安问候。" -[cross_context] # 跨群聊上下文共享配置 +[cross_context] # 跨群聊/私聊上下文共享配置 # 这是总开关,用于一键启用或禁用此功能 -enable = false +enable = true # 在这里定义您的“共享组” -# 只有在同一个组内的群聊才会共享上下文 -# 注意:这里的chat_ids需要填写群号 +# 只有在同一个组内的聊天才会共享上下文 +# 格式:chat_ids = [["type", "id"], ["type", "id"], ...] +# type 可选 "group" 或 "private" [[cross_context.groups]] name = "项目A技术讨论组" chat_ids = [ - "111111", # 假设这是“开发群”的ID - "222222" # 假设这是“产品群”的ID + ["group", "169850076"], # 假设这是“开发群”的ID + ["group", "1025509724"], # 假设这是“产品群”的ID + ["private", "123456789"] # 假设这是某个用户的私聊 ] - [maizone_intercom] # QQ空间互通组配置 # 启用后,发布说说时会读取指定互通组的上下文 @@ -495,6 +496,6 @@ enable = false [[maizone_intercom.groups]] name = "Maizone默认互通组" chat_ids = [ - "111111", # 示例群聊1 - "222222" # 示例群聊2 + ["group", "111111"], # 示例群聊1 + ["private", "222222"] # 示例私聊2 ] \ No newline at end of file