From e0f13ea0ebbdfa9bc6fb3e56bfca2a5eab0207e3 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Fri, 27 Jun 2025 00:29:27 +0800 Subject: [PATCH 1/4] Update changelog.md --- changelogs/changelog.md | 111 +++++++++++----------------------------- 1 file changed, 30 insertions(+), 81 deletions(-) diff --git a/changelogs/changelog.md b/changelogs/changelog.md index 7b69c335f..2c81f150e 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -1,126 +1,75 @@ # Changelog -## [0.8.0] - 2025-1-6 -重大升级!插件系统全面重构,表达方式系统大幅优化,focus大幅降低token花费和反应速度,加入了人物印象系统,麦麦可以记住群友的特点。支持更精细的分群聊天频率控制,normal模式可以使用planner和action +## [0.8.0] - 2025-6-27 -MaiBot 0.8.0 重磅升级!插件系统全面重构,支持更强大的扩展能力;表达方式系统大幅优化,支持智能学习和衰减机制;聊天频率控制更加精细,支持时段化管理;HFC系统性能大幅提升,处理器后置化减少消耗;关系系统升级支持即时构建和人物侧写;日志系统重构使用structlog;大量稳定性修复和性能优化。 +MaiBot 0.8.0 现已推出! -## 🚀 主要更新点 +### **主要升级点:** + +1.插件系统正式加入,现已上线插件商店,同时支持normal和focus +2.大幅降低了token消耗,更省钱 +3.加入人物印象系统,麦麦可以对群友有不同的印象 +4.可以精细化控制不同时段和不同群聊的发言频率 + +#### 其他升级 + +日志系统重构使用structlog +大量稳定性修复和性能优化。 +MMC启动速度加快 + +### 🔌 插系统正式推出 +**全面重构的插件生态系统,支持强大 的扩展能力** -### 🔌 插件系统正式推出 -**全面重构的插件生态系统,支持强大的扩展能力** - **插件API重构**: 全面重构插件系统,统一加载机制,区分内部插件和外部插件 +- **插件仓库**:现可以分享和下载插件 - **依赖管理**: 新增插件依赖管理系统,支持自动注册和依赖检查 - **命令支持**: 插件现已支持命令(command)功能,提供更丰富的交互方式 - **示例插件升级**: 更新禁言插件、豆包绘图插件、TTS插件等示例插件 - **配置文件管理**: 插件支持自动生成和管理配置文件,支持版本自动更新 - **文档完善**: 补全插件API文档,提供详细的开发指南 -- **Action选择优化**: 大大优化action的选择能力,提升动作执行的智能性 - -### ⚡ Focus模式大幅优化 - 降低Token消耗与提升速度 -**HFC系统性能革命性提升,大幅降低成本和提升响应速度** -- **Planner架构更新**: 更新planner架构,大大加快速度和表现效果! -- **处理器重构**: - - 移除旧回复意愿控制系统 - - 精简处理器上下文,减少不必要的处理 - - 后置工具处理器,大大减少token消耗 - - 合并自我处理器和关系处理器,提高效率 - - 可关闭思考处理器(建议默认关闭) -- **统计系统**: 提供focus统计功能,可查看详细的no_reply统计信息 -- **异步优化**: 将统计和person_info改为异步,提升整体性能 ### 👥 人物印象系统 **麦麦现在能认得群友,记住每个人的特点** - **人物侧写功能**: 加入了人物侧写!麦麦现在能认得群友,新增用户侧写功能,将印象拆分为多方面特点 -- **即时构建**: 重构关系构建逻辑,改为即时构建,提高实时性 -- **关系处理器**: 新增专门的关系处理器,支持更精准的关系管理 -- **熟悉度系统**: 添加熟悉度和关系值功能,提供更丰富的关系信息 + +### ⚡ Focus模式大幅优化 - 降低Token消耗与提升速度 +- **Planner架构更新**: 更新planner架构,大大加快速度和表现效果! +- **处理器重构**: + - 移除冗余处理器 + - 精简处理器上下文,减少不必要的处理 + - 后置工具处理器,大大减少token消耗 +- **统计系统**: 提供focus统计功能,可查看详细的no_reply统计信息 + ### ⏰ 聊天频率精细控制 **支持时段化的精细频率管理,让麦麦在合适的时间说合适的话** -- **时段化控制**: 添加时段talk_frequency控制,支持不同时间段的精细频率管理 +- **时段化控制**: 添加时段talk_frequency控制,支持不同时间段不同群聊的精细频率管理 - **严格频率控制**: 实现更加严格和可靠的频率控制机制 - **Normal模式优化**: 大幅优化normal模式的频率控制逻辑,提升回复的智能性 ### 🎭 表达方式系统大幅优化 **智能学习群友聊天风格,让麦麦的表达更加多样化** - **智能学习机制**: 优化表达方式学习算法,支持衰减机制,太久没学的会被自动抛弃 -- **表达方式选择**: 新增表达方式选择处理器,大幅提升表达的多样性 +- **表达方式选择**: 新增表达方式选择器,让表达使用更合理 - **跨群互通配置**: 表达方式现在可以选择在不同群互通或独立 - **可视化工具**: 提供表达方式可视化脚本和检查脚本 -- **人格表达优化**: 修复人格表达生成太固定的问题,增加表达方式的多样性 ### 💾 记忆系统改进 **更快的记忆处理和更好的短期记忆管理** - **海马体优化**: 大大优化海马体同步速度,提升记忆处理效率 -- **记忆同步优化**: 优化记忆同步算法,修复记忆构建缺少chat_id的问题 - **工作记忆升级**: 精简升级工作记忆模块,提供更好的短期记忆管理 - **聊天记录构建**: 优化聊天记录构建方式,提升记忆提取效率 ### 📊 日志系统重构 **使用structlog提供更好的结构化日志** - **structlog替换**: 使用structlog替代loguru,提供更好的结构化日志 -- **日志查看器**: 新增更强大的日志查看器,支持更好的日志浏览 +- **日志查看器**: 新增日志查看脚本,支持更好的日志浏览 - **可配置日志**: 提供可配置的日志级别和格式,支持不同环境的需求 -## 🔧 优化修复点 - -### 🛠️ 开发体验提升 -- **API系统扩展**: - - **Chat Stream API**: 提供获取Chat_stream的API接口 - - **统计API**: 支持统计数据输出API - - **插件API扩展**: 新增多个插件相关的API接口 - - **API重构**: 重构插件API架构,提供更完善的接口体系 -- **Docker部署优化**: - - **配置更新**: 更新docker-compose配置,优化端口映射和服务配置 - - **部署文档**: 优化Docker构建流程和部署文档 - -### 🐛 重要问题修复 -#### 稳定性修复 -- **模式切换**: 修复无法退出专注模式的问题,优化auto模式切换逻辑 -- **循环异常**: 修复循环异常思索问题,提高系统稳定性 -- **插件重载**: 解决插件重复加载问题,增加重复加载警告机制 -- **SQL问题**: 修复数据库相关的SQL问题和索引创建失败问题 -- **性能优化**: 修复日志占用和文件层级问题,解决too many open files问题 - -#### 功能修复 -- **display_name问题**: 修复base_command和base_action中未使用display_name的错误 -- **消息截断**: 修复被指令截断的消息无法保存到prompt的问题 -- **统计数据**: 修复统计相关的多个问题 -- **图片处理**: 优化图片展示形式,修复图片发送相关问题 -- **群名称**: 修复群名称导致log保存失败的问题 -- **Focus首条消息**: 修复focus吞掉首条消息的问题 -- **关键词功能**: 修复关键词功能,并且在focus中可用 -- **表情包Action**: 修复了表情包action相关问题 -- **Focus时间信息**: 修复focus没有时间信息的问题 - -### ⚙️ 配置与性能优化 -- **配置系统增强**: - - **新配置项**: 添加大量新的配置项,支持更细粒度的控制 - - **版本管理**: 支持插件配置文件版本自动更新 - - **模板更新**: 更新bot_config_template.toml配置文件模板 - - **关闭选项**: 可关闭记忆和关系系统、消息后处理等功能 -- **性能优化**: - - **Token优化**: 移除部分不必要的token限制,优化token消耗 - - **异步改进**: 人格表达和remote请求改为异步,不阻塞主线程 - - **内存优化**: 优化工作记忆处理器性能和内存使用 - - **Normal动作执行**: 为normal_chat加入动作执行能力 - -### 📚 文档与工具 -- **文档完善**: - - **插件开发指南**: 提供详细的插件系统开发文档 - - **API文档**: 补全插件API文档和使用说明 - - **部署指南**: 优化部署相关文档的完整性 -- **辅助工具**: - - **表达方式工具**: 提供表达方式检查脚本和可视化工具 - - **插件管理工具**: 新增插件和清单管理工具 - - **关系构建脚本**: 提供关系构建和回溯脚本 - ### 🎯 其他改进 - **emoji系统**: 移除emoji默认发送模式,优化表情包审查功能 - **控制台发送**: 添加不完善的控制台发送功能 - **行为准则**: 添加贡献者契约行为准则 -- **代码质量**: 使用ruff进行代码格式化和质量检查 - **图像清理**: 自动清理images文件夹,优化存储空间使用 From 5f67774f6a668cfa3854a547026762a0ee51606a Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Fri, 27 Jun 2025 00:30:13 +0800 Subject: [PATCH 2/4] =?UTF-8?q?better:=E4=BC=98=E5=8C=96=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/express/expression_selector.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/chat/express/expression_selector.py b/src/chat/express/expression_selector.py index 11eccb91e..21b0a16b2 100644 --- a/src/chat/express/expression_selector.py +++ b/src/chat/express/expression_selector.py @@ -15,11 +15,11 @@ logger = get_logger("expression_selector") def init_prompt(): expression_evaluation_prompt = """ -你的名字是{bot_name} - 以下是正在进行的聊天内容: {chat_observe_info} +你的名字是{bot_name}{target_message} + 以下是可选的表达情境: {all_situations} @@ -28,6 +28,7 @@ def init_prompt(): 1. 聊天的情绪氛围(轻松、严肃、幽默等) 2. 话题类型(日常、技术、游戏、情感等) 3. 情境与当前语境的匹配度 +{target_message_extra_block} 请以JSON格式输出,只需要输出选中的情境编号: 例如: @@ -156,7 +157,7 @@ class ExpressionSelector: new_count = min(current_count + increment, 5.0) expr_in_map["count"] = new_count expr_in_map["last_active_time"] = time.time() - logger.info( + logger.debug( f"表达方式激活: 原count={current_count:.3f}, 增量={increment}, 新count={new_count:.3f} in {file_path}" ) @@ -168,7 +169,7 @@ class ExpressionSelector: logger.error(f"批量更新表达方式count失败 for {file_path}: {e}") async def select_suitable_expressions_llm( - self, chat_id: str, chat_info: str, max_num: int = 10, min_num: int = 5 + self, chat_id: str, chat_info: str, max_num: int = 10, min_num: int = 5, target_message: str = None ) -> List[Dict[str, str]]: """使用LLM选择适合的表达方式""" @@ -208,7 +209,14 @@ class ExpressionSelector: return [] all_situations_str = "\n".join(all_situations) - + + if target_message: + target_message_str = f",现在你想要回复消息:{target_message}" + target_message_extra_block = f"4.考虑你要回复的目标消息" + else: + target_message_str = "" + target_message_extra_block = "" + # 3. 构建prompt(只包含情境,不包含完整的表达方式) prompt = (await global_prompt_manager.get_prompt_async("expression_evaluation_prompt")).format( bot_name=global_config.bot.nickname, @@ -216,7 +224,11 @@ class ExpressionSelector: all_situations=all_situations_str, min_num=min_num, max_num=max_num, + target_message=target_message_str, + target_message_extra_block=target_message_extra_block, ) + + # print(prompt) # 4. 调用LLM try: From a411aa3da44a270661475273848bbb31d157129e Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Fri, 27 Jun 2025 00:30:45 +0800 Subject: [PATCH 3/4] =?UTF-8?q?better=EF=BC=9A=E6=9B=B4=E5=A5=BD=E7=9A=84?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/focus_chat/heartFC_chat.py | 144 +------ .../focus_chat/heartflow_message_processor.py | 15 +- .../expression_selector_processor.py | 15 +- .../info_processors/relationship_processor.py | 362 +++++++----------- .../info_processors/tool_processor.py | 19 +- .../focus_chat/planners/modify_actions.py | 2 +- src/chat/normal_chat/normal_chat.py | 4 +- src/plugin_system/apis/llm_api.py | 4 +- src/plugins/built_in/core_actions/no_reply.py | 9 +- 9 files changed, 199 insertions(+), 375 deletions(-) diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index ae18f3885..7704986f8 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -413,7 +413,6 @@ class HeartFChatting: "action_result": { "action_type": "error", "action_data": {}, - "reasoning": f"上下文处理失败: {e}", }, "observed_messages": "", }, @@ -650,143 +649,9 @@ class HeartFChatting: return all_plan_info, processor_time_costs - async def _process_post_planning_processors(self, observations: List[Observation], action_data: dict) -> dict: - """ - 处理后期处理器(规划后执行的处理器) - 包括:关系处理器、表达选择器、记忆激活器 - - 参数: - observations: 观察器列表 - action_data: 原始动作数据 - - 返回: - dict: 更新后的动作数据 - """ - logger.info(f"{self.log_prefix} 开始执行后期处理器") - - # 创建所有后期任务 - task_list = [] - task_to_name_map = {} - - # 添加后期处理器任务 - for processor in self.post_planning_processors: - processor_name = processor.__class__.__name__ - - async def run_processor_with_timeout(proc=processor): - return await asyncio.wait_for( - proc.process_info(observations=observations), - timeout=global_config.focus_chat.processor_max_time, - ) - - task = asyncio.create_task(run_processor_with_timeout()) - task_list.append(task) - task_to_name_map[task] = ("processor", processor_name) - logger.info(f"{self.log_prefix} 启动后期处理器任务: {processor_name}") - - # 添加记忆激活器任务 - async def run_memory_with_timeout(): - return await asyncio.wait_for( - self.memory_activator.activate_memory(observations), - timeout=MEMORY_ACTIVATION_TIMEOUT, - ) - - memory_task = asyncio.create_task(run_memory_with_timeout()) - task_list.append(memory_task) - task_to_name_map[memory_task] = ("memory", "MemoryActivator") - logger.info(f"{self.log_prefix} 启动记忆激活器任务") - - # 如果没有任何后期任务,直接返回 - if not task_list: - logger.info(f"{self.log_prefix} 没有启用的后期处理器或记忆激活器") - return action_data - - # 等待所有任务完成 - pending_tasks = set(task_list) - all_post_plan_info = [] - running_memorys = [] - - while pending_tasks: - done, pending_tasks = await asyncio.wait(pending_tasks, return_when=asyncio.FIRST_COMPLETED) - - for task in done: - task_type, task_name = task_to_name_map[task] - - try: - result = await task - - if task_type == "processor": - logger.info(f"{self.log_prefix} 后期处理器 {task_name} 已完成!") - if result is not None: - all_post_plan_info.extend(result) - else: - logger.warning(f"{self.log_prefix} 后期处理器 {task_name} 返回了 None") - elif task_type == "memory": - logger.info(f"{self.log_prefix} 记忆激活器已完成!") - if result is not None: - running_memorys = result - else: - logger.warning(f"{self.log_prefix} 记忆激活器返回了 None") - running_memorys = [] - - except asyncio.TimeoutError: - if task_type == "processor": - logger.warning( - f"{self.log_prefix} 后期处理器 {task_name} 超时(>{global_config.focus_chat.processor_max_time}s),已跳过" - ) - elif task_type == "memory": - logger.warning(f"{self.log_prefix} 记忆激活器超时(>{MEMORY_ACTIVATION_TIMEOUT}s),已跳过") - running_memorys = [] - except Exception as e: - if task_type == "processor": - logger.error( - f"{self.log_prefix} 后期处理器 {task_name} 执行失败. 错误: {e}", - exc_info=True, - ) - elif task_type == "memory": - logger.error(f"{self.log_prefix} 记忆激活器执行失败. 错误: {e}", exc_info=True) - running_memorys = [] - - # 将后期处理器的结果整合到 action_data 中 - updated_action_data = action_data.copy() - - relation_info = "" - selected_expressions = [] - structured_info = "" - - for info in all_post_plan_info: - if isinstance(info, RelationInfo): - relation_info = info.get_processed_info() - elif isinstance(info, ExpressionSelectionInfo): - selected_expressions = info.get_expressions_for_action_data() - elif isinstance(info, StructuredInfo): - structured_info = info.get_processed_info() - - if relation_info: - updated_action_data["relation_info_block"] = relation_info - - if selected_expressions: - updated_action_data["selected_expressions"] = selected_expressions - - if structured_info: - updated_action_data["structured_info"] = structured_info - - # 特殊处理running_memorys - if running_memorys: - memory_str = "以下是当前在聊天中,你回忆起的记忆:\n" - for running_memory in running_memorys: - memory_str += f"{running_memory['content']}\n" - updated_action_data["memory_block"] = memory_str - logger.info(f"{self.log_prefix} 添加了 {len(running_memorys)} 个激活的记忆到action_data") - - if all_post_plan_info or running_memorys: - logger.info( - f"{self.log_prefix} 后期处理完成,产生了 {len(all_post_plan_info)} 个信息项和 {len(running_memorys)} 个记忆" - ) - - return updated_action_data async def _process_post_planning_processors_with_timing( - self, observations: List[Observation], action_data: dict + self, observations: List[Observation], action_type: str, action_data: dict ) -> tuple[dict, dict]: """ 处理后期处理器(规划后执行的处理器)并收集详细时间统计 @@ -794,6 +659,7 @@ class HeartFChatting: 参数: observations: 观察器列表 + action_type: 动作类型 action_data: 原始动作数据 返回: @@ -815,7 +681,9 @@ class HeartFChatting: start_time = time.time() try: result = await asyncio.wait_for( - proc.process_info(observations=observations), + proc.process_info( + observations=observations, action_type=action_type, action_data=action_data + ), timeout=global_config.focus_chat.processor_max_time, ) end_time = time.time() @@ -1074,7 +942,7 @@ class HeartFChatting: # 记录详细的后处理器时间 post_start_time = time.time() action_data, post_processor_time_costs = await self._process_post_planning_processors_with_timing( - self.observations, action_data + self.observations, action_type, action_data ) post_end_time = time.time() logger.info(f"{self.log_prefix} 后期处理器总耗时: {post_end_time - post_start_time:.3f}秒") diff --git a/src/chat/focus_chat/heartflow_message_processor.py b/src/chat/focus_chat/heartflow_message_processor.py index e73208791..ad5890270 100644 --- a/src/chat/focus_chat/heartflow_message_processor.py +++ b/src/chat/focus_chat/heartflow_message_processor.py @@ -181,9 +181,18 @@ class HeartFCMessageReceiver: mes_name = chat.group_info.group_name if chat.group_info else "私聊" # current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time)) current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id) - logger.info( - f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]" - ) + + # 如果消息中包含图片标识,则日志展示为图片 + import re + picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text) + if picid_match: + logger.info( + f"[{mes_name}]{userinfo.user_nickname}: [图片] [当前回复频率: {current_talk_frequency}]" + ) + else: + logger.info( + f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]" + ) # 8. 关系处理 if global_config.relationship.enable_relationship: diff --git a/src/chat/focus_chat/info_processors/expression_selector_processor.py b/src/chat/focus_chat/info_processors/expression_selector_processor.py index f916f0362..66b199718 100644 --- a/src/chat/focus_chat/info_processors/expression_selector_processor.py +++ b/src/chat/focus_chat/info_processors/expression_selector_processor.py @@ -27,7 +27,13 @@ class ExpressionSelectorProcessor(BaseProcessor): name = get_chat_manager().get_stream_name(self.subheartflow_id) self.log_prefix = f"[{name}] 表达选择器" - async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]: + async def process_info( + self, + observations: List[Observation] = None, + action_type: str = None, + action_data: dict = None, + **kwargs, + ) -> List[InfoBase]: """处理信息对象 Args: @@ -70,9 +76,14 @@ class ExpressionSelectorProcessor(BaseProcessor): return [] try: + if action_type == "reply": + target_message = action_data.get("reply_to", "") + else: + target_message = "" + # LLM模式:调用LLM选择5-10个,然后随机选5个 selected_expressions = await expression_selector.select_suitable_expressions_llm( - self.subheartflow_id, chat_info, max_num=12, min_num=2 + self.subheartflow_id, chat_info, max_num=12, min_num=2, target_message=target_message ) cache_size = len(selected_expressions) if selected_expressions else 0 mode_desc = f"LLM模式(已缓存{cache_size}个)" diff --git a/src/chat/focus_chat/info_processors/relationship_processor.py b/src/chat/focus_chat/info_processors/relationship_processor.py index b6fdda66f..d4573fcad 100644 --- a/src/chat/focus_chat/info_processors/relationship_processor.py +++ b/src/chat/focus_chat/info_processors/relationship_processor.py @@ -37,139 +37,51 @@ SEGMENT_CLEANUP_CONFIG = { "cleanup_interval_hours": 1, # 清理间隔(小时) } -# 用于随机生成prompt示例的资源池 -USER_EXAMPLE_KEYS = ["用户A", "小明", "Alice", "陈皮", "老王", "Bob", "张三", "李四"] -USER_EXAMPLE_VALUES = [ - "ta的昵称", - "ta对你的态度", - "你对ta的印象", - "ta最近心情如何", - "你们的关系", - "ta的身份", - "ta的兴趣爱好", - "ta和你的共同点", - "ta的习惯", - "你们最近做的事", - "你对ta的语气", - "你们的互动方式", - "给你的第一印象", - "你们最近聊过什么", -] -BOT_EXAMPLE_VALUES = [ - "身份", - "性格", - "你的原则", - "你的知识", - "你的目标", - "你的爱好", - "你最近在做什么", - "头像", - "年龄", - "性别", - "职业", - "兴趣爱好", - "习惯", - "目标", - "原则", - "知识", - "爱好", -] - logger = get_logger("processor") -def _generate_random_prompt_example() -> str: - """动态生成一个随机的、符合规则的JSON示例字符串""" - - bot_nickname = global_config.bot.nickname - bot_aliases = list(global_config.bot.alias_names) - - # 确定示例数量 - num_user_examples = random.randint(1, 2) - num_bot_examples = random.randint(1, 2) - - example_dict = {} - - # 1. 生成用户提取示例 - user_keys = random.sample(USER_EXAMPLE_KEYS, min(num_user_examples, len(USER_EXAMPLE_KEYS))) - user_values = random.sample(USER_EXAMPLE_VALUES, min(num_user_examples, len(USER_EXAMPLE_VALUES))) - for i in range(len(user_keys)): - example_dict[user_keys[i]] = user_values[i] - - # 2. 生成bot自身示例 (使用昵称和别名避免key重复) - bot_name_pool = [bot_nickname] + bot_aliases - random.shuffle(bot_name_pool) - bot_values = random.sample(BOT_EXAMPLE_VALUES, min(num_bot_examples, len(BOT_EXAMPLE_VALUES))) - - for i in range(min(num_bot_examples, len(bot_name_pool), len(bot_values))): - example_dict[bot_name_pool[i]] = bot_values[i] - - # 3. 添加固定示例 - example_dict["person_name"] = "其他信息" - - # 随机化顺序并格式化为JSON字符串 - items = list(example_dict.items()) - random.shuffle(items) - shuffled_dict = dict(items) - - return json.dumps(shuffled_dict, ensure_ascii=False, indent=4) - - def init_prompt(): relationship_prompt = """ <聊天记录> {chat_observe_info} -{info_cache_block} -请不要重复调取相同的信息 - {name_block} -请你阅读聊天记录,查看是否需要调取某个人的信息,这个人可以是出现在聊天记录中的,也可以是记录中提到的人,也可以是你自己({bot_name})。 -你不同程度上认识群聊里的人,以及他们谈论到的人,你可以根据聊天记录,回忆起有关他们的信息,帮助你参与聊天 -1.你需要提供用户名和你想要提取的信息名称类型来进行调取 -2.请注意,提取的信息类型一定要和用户有关,不要提取无关的信息 -3.你也可以调取有关自己({bot_name})的信息 -4.如果当前聊天记录中没有需要查询的信息,或者现有信息已经足够回复,请返回{{"none": "不需要查询"}} +现在,你想要回复{person_name}的消息,消息内容是:{target_message}。请根据聊天记录和你要回复的消息,从你对{person_name}的了解中提取有关的信息: +1.你需要提供你想要提取的信息具体是哪方面的信息,例如:年龄,性别,对ta的印象,最近发生的事等等。 +2.请注意,请不要重复调取相同的信息,已经调取的信息如下: +{info_cache_block} +3.如果当前聊天记录中没有需要查询的信息,或者现有信息已经足够回复,请返回{{"none": "不需要查询"}} 请以json格式输出,例如: -{example_json} - -如果不需要查询任何信息,请输出: -{{"none": "不需要查询"}} - -请严格按照json输出格式,不要输出多余内容,可以同时查询多个人的信息: +{{ + "info_type": "信息类型", +}} +请严格按照json输出格式,不要输出多余内容: """ Prompt(relationship_prompt, "relationship_prompt") fetch_info_prompt = """ {name_block} -以下是你在之前与{person_name}的交流中,产生的对{person_name}的了解,请你从中提取用户的有关"{info_type}"的信息,如果用户没有相关信息,请输出none: +以下是你在之前与{person_name}的交流中,产生的对{person_name}的了解: {person_impression_block} {points_text_block} -请严格按照以下json输出格式,不要输出多余内容: + +请从中提取用户"{person_name}"的有关"{info_type}"信息 +请以json格式输出,例如: + {{ {info_json_str} }} + +请严格按照json输出格式,不要输出多余内容: """ Prompt(fetch_info_prompt, "fetch_person_info_prompt") - fetch_bot_info_prompt = """ -你是{nickname},你的昵称有{alias_names}。 -以下是你对自己的了解,请你从中提取和"{info_type}"有关的信息,如果无法提取,请输出none: -{person_impression_block} -{points_text_block} -请严格按照以下json输出格式,不要输出多余内容: -{{ - "{info_type}": "有关你自己的{info_type}的信息内容" -}} -""" - Prompt(fetch_bot_info_prompt, "fetch_bot_info_prompt") - class PersonImpressionpProcessor(BaseProcessor): log_prefix = "关系" @@ -293,7 +205,7 @@ class PersonImpressionpProcessor(BaseProcessor): } segments.append(new_segment) - person_name = get_person_info_manager().get_value(person_id, "person_name") or person_id + person_name = get_person_info_manager().get_value_sync(person_id, "person_name") or person_id logger.info( f"{self.log_prefix} 眼熟用户 {person_name} 在 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))} 之间有 {new_segment['message_count']} 条消息" ) @@ -341,7 +253,8 @@ class PersonImpressionpProcessor(BaseProcessor): "message_count": self._count_messages_in_timerange(potential_start_time, message_time), } segments.append(new_segment) - person_name = get_person_info_manager().get_value(person_id, "person_name") or person_id + person_info_manager = get_person_info_manager() + person_name = person_info_manager.get_value_sync(person_id, "person_name") or person_id logger.info(f"{self.log_prefix} 重新眼熟用户 {person_name} 创建新消息段(超过10条消息间隔): {new_segment}") self._save_cache() @@ -515,16 +428,26 @@ class PersonImpressionpProcessor(BaseProcessor): # 统筹各模块协作、对外提供服务接口 # ================================ - async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]: + async def process_info( + self, + observations: List[Observation] = None, + action_type: str = None, + action_data: dict = None, + **kwargs, + ) -> List[InfoBase]: """处理信息对象 Args: - *infos: 可变数量的InfoBase类型的信息对象 + observations: 观察对象列表 + action_type: 动作类型 + action_data: 动作数据 Returns: List[InfoBase]: 处理后的结构化信息列表 """ - relation_info_str = await self.relation_identify(observations) + await self.build_relation(observations) + + relation_info_str = await self.relation_identify(observations,action_type,action_data) if relation_info_str: relation_info = RelationInfo() @@ -535,28 +458,14 @@ class PersonImpressionpProcessor(BaseProcessor): return [relation_info] - async def relation_identify( - self, - observations: List[Observation] = None, - ): - """ - 在回复前进行思考,生成内心想法并收集工具调用结果 - """ - # 0. 执行定期清理 + async def build_relation(self, observations: List[Observation] = None): + """构建关系""" self._cleanup_old_segments() - - # 1. 从观察信息中提取所需数据 - # 需要兼容私聊 - - chat_observe_info = "" current_time = time.time() + if observations: for observation in observations: if isinstance(observation, ChattingObservation): - chat_observe_info = observation.get_observe_info() - # latest_message_time = observation.last_observe_time - # 从聊天观察中提取用户信息并更新消息段 - # 获取最新的非bot消息来更新消息段 latest_messages = get_raw_msg_by_timestamp_with_chat( self.subheartflow_id, self.last_processed_message_time, @@ -609,6 +518,55 @@ class PersonImpressionpProcessor(BaseProcessor): # 移除已处理的用户缓存 del self.person_engaged_cache[person_id] self._save_cache() + + async def relation_identify( + self, + observations: List[Observation] = None, + action_type: str = None, + action_data: dict = None, + ): + """ + 从人物获取信息 + """ + + chat_observe_info = "" + current_time = time.time() + if observations: + for observation in observations: + if isinstance(observation, ChattingObservation): + chat_observe_info = observation.get_observe_info() + # latest_message_time = observation.last_observe_time + # 从聊天观察中提取用户信息并更新消息段 + # 获取最新的非bot消息来更新消息段 + latest_messages = get_raw_msg_by_timestamp_with_chat( + self.subheartflow_id, + self.last_processed_message_time, + current_time, + limit=50, # 获取自上次处理后的消息 + ) + if latest_messages: + # 处理所有新的非bot消息 + for latest_msg in latest_messages: + user_id = latest_msg.get("user_id") + platform = latest_msg.get("user_platform") or latest_msg.get("chat_info_platform") + msg_time = latest_msg.get("time", 0) + + if ( + user_id + and platform + and user_id != global_config.bot.qq_account + and msg_time > self.last_processed_message_time + ): + from src.person_info.person_info import PersonInfoManager + + person_id = PersonInfoManager.get_person_id(platform, user_id) + self._update_message_segments(person_id, msg_time) + logger.debug( + f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}" + ) + self.last_processed_message_time = max(self.last_processed_message_time, msg_time) + break + for person_id in list(self.info_fetched_cache.keys()): for info_type in list(self.info_fetched_cache[person_id].keys()): @@ -617,8 +575,38 @@ class PersonImpressionpProcessor(BaseProcessor): del self.info_fetched_cache[person_id][info_type] if not self.info_fetched_cache[person_id]: del self.info_fetched_cache[person_id] + + + + + + if action_type != "reply": + return None + + target_message = action_data.get("reply_to", "") + + if ":" in target_message: + parts = target_message.split(":", 1) + elif ":" in target_message: + parts = target_message.split(":", 1) + else: + logger.warning(f"reply_to格式不正确: {target_message},跳过关系识别") + return None + + if len(parts) != 2: + logger.warning(f"reply_to格式不正确: {target_message},跳过关系识别") + return None + + sender = parts[0].strip() + text = parts[1].strip() + + person_info_manager = get_person_info_manager() + person_id = person_info_manager.get_person_id_by_person_name(sender) + + if not person_id: + logger.warning(f"未找到用户 {sender} 的ID,跳过关系识别") + return None - # 5. 为需要处理的人员准备LLM prompt nickname_str = ",".join(global_config.bot.alias_names) name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" @@ -638,19 +626,16 @@ class PersonImpressionpProcessor(BaseProcessor): f"你已经调取了[{info_fetching['person_name']}]的[{info_fetching['info_type']}]信息\n" ) - example_json = _generate_random_prompt_example() - prompt = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format( - name_block=name_block, - bot_name=global_config.bot.nickname, - time_now=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), chat_observe_info=chat_observe_info, + name_block=name_block, info_cache_block=info_cache_block, - example_json=example_json, + person_name=sender, + target_message=text, ) try: - logger.debug(f"{self.log_prefix} 人物信息prompt: \n{prompt}\n") + logger.info(f"{self.log_prefix} 人物信息prompt: \n{prompt}\n") content, _ = await self.llm_model.generate_response_async(prompt=prompt) if content: # print(f"content: {content}") @@ -661,29 +646,12 @@ class PersonImpressionpProcessor(BaseProcessor): logger.info(f"{self.log_prefix} LLM判断当前不需要查询任何信息:{content_json.get('none', '')}") # 跳过新的信息提取,但仍会处理已有缓存 else: - # 收集即时提取任务 - instant_tasks = [] - async_tasks = [] - - person_info_manager = get_person_info_manager() - for person_name, info_type in content_json.items(): - is_bot = ( - person_name == global_config.bot.nickname or person_name in global_config.bot.alias_names - ) - if is_bot: - person_id = person_info_manager.get_person_id("system", "bot_id") - logger.info(f"{self.log_prefix} 检测到对bot自身({person_name})的信息查询,使用特殊ID。") - else: - person_id = person_info_manager.get_person_id_by_person_name(person_name) - - if not person_id: - logger.warning(f"{self.log_prefix} 未找到用户 {person_name} 的ID,跳过调取信息。") - continue - + info_type = content_json.get("info_type") + if info_type: self.info_fetching_cache.append( { "person_id": person_id, - "person_name": person_name, + "person_name": sender, "info_type": info_type, "start_time": time.time(), "forget": False, @@ -692,22 +660,12 @@ class PersonImpressionpProcessor(BaseProcessor): if len(self.info_fetching_cache) > 20: self.info_fetching_cache.pop(0) - logger.info(f"{self.log_prefix} 调取用户 {person_name} 的 {info_type} 信息。") + logger.info(f"{self.log_prefix} 调取用户 {sender} 的[{info_type}]信息。") - # 收集即时提取任务 - instant_tasks.append((person_id, info_type, time.time())) - - # 执行即时提取任务 - if instant_tasks: - await self._execute_instant_extraction_batch(instant_tasks) - - # 启动异步任务(如果不是即时模式) - if async_tasks: - # 异步任务不需要等待完成 - pass - - else: - logger.warning(f"{self.log_prefix} LLM返回空结果,关系识别失败。") + # 执行信息提取 + await self._fetch_single_info_instant(person_id, info_type, time.time()) + else: + logger.warning(f"{self.log_prefix} LLM did not return a valid info_type. Response: {content}") except Exception as e: logger.error(f"{self.log_prefix} 执行LLM请求或处理响应时出错: {e}") @@ -838,31 +796,6 @@ class PersonImpressionpProcessor(BaseProcessor): # 负责实时分析对话需求、提取用户信息、管理信息缓存 # ================================ - async def _execute_instant_extraction_batch(self, instant_tasks: list): - """ - 批量执行即时提取任务 - """ - if not instant_tasks: - return - - logger.info(f"{self.log_prefix} [即时提取] 开始批量提取 {len(instant_tasks)} 个信息") - - # 创建所有提取任务 - extraction_tasks = [] - for person_id, info_type, start_time in instant_tasks: - # 检查缓存中是否已存在且未过期的信息 - if person_id in self.info_fetched_cache and info_type in self.info_fetched_cache[person_id]: - logger.debug(f"{self.log_prefix} 用户 {person_id} 的 {info_type} 信息已存在且未过期,跳过调取。") - continue - - task = asyncio.create_task(self._fetch_single_info_instant(person_id, info_type, start_time)) - extraction_tasks.append(task) - - # 并行执行所有提取任务并等待完成 - if extraction_tasks: - await asyncio.gather(*extraction_tasks, return_exceptions=True) - logger.info(f"{self.log_prefix} [即时提取] 批量提取完成") - async def _fetch_single_info_instant(self, person_id: str, info_type: str, start_time: float): """ 使用小模型提取单个信息类型 @@ -890,7 +823,7 @@ class PersonImpressionpProcessor(BaseProcessor): self.info_fetched_cache[person_id][info_type] = { "info": cached_info, - "ttl": 4, + "ttl": 2, "start_time": start_time, "person_name": person_name, "unknow": cached_info == "none", @@ -898,8 +831,6 @@ class PersonImpressionpProcessor(BaseProcessor): logger.info(f"{self.log_prefix} 记得 {person_name} 的 {info_type}: {cached_info}") return - bot_person_id = PersonInfoManager.get_person_id("system", "bot_id") - is_bot = person_id == bot_person_id try: person_name = await person_info_manager.get_value(person_id, "person_name") @@ -923,7 +854,7 @@ class PersonImpressionpProcessor(BaseProcessor): self.info_fetched_cache[person_id] = {} self.info_fetched_cache[person_id][info_type] = { "info": "none", - "ttl": 4, + "ttl": 2, "start_time": start_time, "person_name": person_name, "unknow": True, @@ -932,27 +863,18 @@ class PersonImpressionpProcessor(BaseProcessor): await self._save_info_to_cache(person_id, info_type, "none") return - if is_bot: - prompt = (await global_prompt_manager.get_prompt_async("fetch_bot_info_prompt")).format( - nickname=global_config.bot.nickname, - alias_names=",".join(global_config.bot.alias_names), - info_type=info_type, - person_impression_block=person_impression_block, - points_text_block=points_text_block, - ) - else: - nickname_str = ",".join(global_config.bot.alias_names) - name_block = ( - f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" - ) - prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format( - name_block=name_block, - info_type=info_type, - person_impression_block=person_impression_block, - person_name=person_name, - info_json_str=f'"{info_type}": "有关{info_type}的信息内容"', - points_text_block=points_text_block, - ) + nickname_str = ",".join(global_config.bot.alias_names) + name_block = ( + f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" + ) + prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format( + name_block=name_block, + info_type=info_type, + person_impression_block=person_impression_block, + person_name=person_name, + info_json_str=f'"{info_type}": "有关{info_type}的信息内容"', + points_text_block=points_text_block, + ) except Exception: logger.error(traceback.format_exc()) return @@ -972,7 +894,7 @@ class PersonImpressionpProcessor(BaseProcessor): self.info_fetched_cache[person_id] = {} self.info_fetched_cache[person_id][info_type] = { "info": "unknow" if is_unknown else info_content, - "ttl": 8, + "ttl": 3, "start_time": start_time, "person_name": person_name, "unknow": is_unknown, diff --git a/src/chat/focus_chat/info_processors/tool_processor.py b/src/chat/focus_chat/info_processors/tool_processor.py index 682f87f87..51bc4529e 100644 --- a/src/chat/focus_chat/info_processors/tool_processor.py +++ b/src/chat/focus_chat/info_processors/tool_processor.py @@ -47,13 +47,20 @@ class ToolProcessor(BaseProcessor): ) self.structured_info = [] - async def process_info(self, observations: Optional[List[Observation]] = None) -> List[StructuredInfo]: + async def process_info( + self, + observations: List[Observation] = None, + action_type: str = None, + action_data: dict = None, + **kwargs, + ) -> List[StructuredInfo]: """处理信息对象 Args: observations: 可选的观察列表,包含ChattingObservation和StructureObservation类型 - running_memories: 可选的运行时记忆列表,包含字典类型的记忆信息 - *infos: 可变数量的InfoBase类型的信息对象 + action_type: 动作类型 + action_data: 动作数据 + **kwargs: 其他可选参数 Returns: list: 处理后的结构化信息列表 @@ -85,7 +92,9 @@ class ToolProcessor(BaseProcessor): return [structured_info] - async def execute_tools(self, observation: ChattingObservation): + async def execute_tools( + self, observation: ChattingObservation, action_type: str = None, action_data: dict = None + ): """ 并行执行工具,返回结构化信息 @@ -95,6 +104,8 @@ class ToolProcessor(BaseProcessor): is_group_chat: 是否为群聊,默认为False return_details: 是否返回详细信息,默认为False cycle_info: 循环信息对象,可用于记录详细执行信息 + action_type: 动作类型 + action_data: 动作数据 返回: 如果return_details为False: diff --git a/src/chat/focus_chat/planners/modify_actions.py b/src/chat/focus_chat/planners/modify_actions.py index adba72088..1ec25567b 100644 --- a/src/chat/focus_chat/planners/modify_actions.py +++ b/src/chat/focus_chat/planners/modify_actions.py @@ -470,7 +470,7 @@ class ActionModifier: response = response.strip().lower() # print(base_prompt) - print(f"LLM判定动作 {action_name}:响应='{response}'") + # print(f"LLM判定动作 {action_name}:响应='{response}'") should_activate = "是" in response or "yes" in response or "true" in response diff --git a/src/chat/normal_chat/normal_chat.py b/src/chat/normal_chat/normal_chat.py index 0af1877fa..2b9777fba 100644 --- a/src/chat/normal_chat/normal_chat.py +++ b/src/chat/normal_chat/normal_chat.py @@ -183,7 +183,7 @@ class NormalChat: "message_count": self._count_messages_in_timerange(potential_start_time, message_time), } segments.append(new_segment) - logger.info( + logger.debug( f"[{self.stream_name}] 为用户 {person_id} 创建新消息段: 时间范围 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))}, 消息数: {new_segment['message_count']}" ) self._save_cache() @@ -230,7 +230,7 @@ class NormalChat: "message_count": self._count_messages_in_timerange(potential_start_time, message_time), } segments.append(new_segment) - logger.info(f"[{self.stream_name}] 为用户 {person_id} 创建新消息段(超过10条消息间隔): {new_segment}") + logger.debug(f"[{self.stream_name}] 为用户 {person_id} 创建新消息段(超过10条消息间隔): {new_segment}") self._save_cache() diff --git a/src/plugin_system/apis/llm_api.py b/src/plugin_system/apis/llm_api.py index 9dbbeeb9d..1bcd1f7d2 100644 --- a/src/plugin_system/apis/llm_api.py +++ b/src/plugin_system/apis/llm_api.py @@ -53,7 +53,9 @@ async def generate_with_model( Tuple[bool, str, str, str]: (是否成功, 生成的内容, 推理过程, 模型名称) """ try: - logger.info(f"[LLMAPI] 使用模型生成内容,提示词: {prompt[:200]}...") + model_name = model_config.get("name") + logger.info(f"[LLMAPI] 使用模型 {model_name} 生成内容") + logger.debug(f"[LLMAPI] 完整提示词: {prompt}") llm_request = LLMRequest(model=model_config, request_type=request_type, **kwargs) diff --git a/src/plugins/built_in/core_actions/no_reply.py b/src/plugins/built_in/core_actions/no_reply.py index c38adb83e..f480886ce 100644 --- a/src/plugins/built_in/core_actions/no_reply.py +++ b/src/plugins/built_in/core_actions/no_reply.py @@ -343,14 +343,15 @@ class NoReplyAction(BaseAction): if success and response: response = response.strip() - logger.info(f"{self.log_prefix} 模型({model_name})原始JSON响应: {response}") + logger.debug(f"{self.log_prefix} 模型({model_name})原始JSON响应: {response}") # 解析LLM的JSON响应,提取判断结果和理由 judge_result, reason = self._parse_llm_judge_response(response) - logger.info( - f"{self.log_prefix} JSON解析结果 - 判断: {judge_result}, 理由: {reason}" - ) + if judge_result: + logger.info(f"{self.log_prefix} 决定继续参与讨论,结束等待,原因: {reason}") + else: + logger.info(f"{self.log_prefix} 决定不参与讨论,继续等待,原因: {reason}") # 将判断结果保存到历史中 judge_history.append((current_time, judge_result, reason)) From 1c57e68f1367e167038d9eb45e0e334f2d9b0705 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 Jun 2025 16:31:07 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/express/expression_selector.py | 8 +++---- src/chat/focus_chat/heartFC_chat.py | 5 +---- .../focus_chat/heartflow_message_processor.py | 7 +++--- .../info_processors/relationship_processor.py | 22 +++++-------------- .../info_processors/tool_processor.py | 6 ++--- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/chat/express/expression_selector.py b/src/chat/express/expression_selector.py index 21b0a16b2..ca63db943 100644 --- a/src/chat/express/expression_selector.py +++ b/src/chat/express/expression_selector.py @@ -209,14 +209,14 @@ class ExpressionSelector: return [] all_situations_str = "\n".join(all_situations) - + if target_message: target_message_str = f",现在你想要回复消息:{target_message}" - target_message_extra_block = f"4.考虑你要回复的目标消息" + target_message_extra_block = "4.考虑你要回复的目标消息" else: target_message_str = "" target_message_extra_block = "" - + # 3. 构建prompt(只包含情境,不包含完整的表达方式) prompt = (await global_prompt_manager.get_prompt_async("expression_evaluation_prompt")).format( bot_name=global_config.bot.nickname, @@ -227,7 +227,7 @@ class ExpressionSelector: target_message=target_message_str, target_message_extra_block=target_message_extra_block, ) - + # print(prompt) # 4. 调用LLM diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 7704986f8..ba1222650 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -649,7 +649,6 @@ class HeartFChatting: return all_plan_info, processor_time_costs - async def _process_post_planning_processors_with_timing( self, observations: List[Observation], action_type: str, action_data: dict ) -> tuple[dict, dict]: @@ -681,9 +680,7 @@ class HeartFChatting: start_time = time.time() try: result = await asyncio.wait_for( - proc.process_info( - observations=observations, action_type=action_type, action_data=action_data - ), + proc.process_info(observations=observations, action_type=action_type, action_data=action_data), timeout=global_config.focus_chat.processor_max_time, ) end_time = time.time() diff --git a/src/chat/focus_chat/heartflow_message_processor.py b/src/chat/focus_chat/heartflow_message_processor.py index ad5890270..d7299d4c6 100644 --- a/src/chat/focus_chat/heartflow_message_processor.py +++ b/src/chat/focus_chat/heartflow_message_processor.py @@ -181,14 +181,13 @@ class HeartFCMessageReceiver: mes_name = chat.group_info.group_name if chat.group_info else "私聊" # current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time)) current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id) - + # 如果消息中包含图片标识,则日志展示为图片 import re + picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text) if picid_match: - logger.info( - f"[{mes_name}]{userinfo.user_nickname}: [图片] [当前回复频率: {current_talk_frequency}]" - ) + logger.info(f"[{mes_name}]{userinfo.user_nickname}: [图片] [当前回复频率: {current_talk_frequency}]") else: logger.info( f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]" diff --git a/src/chat/focus_chat/info_processors/relationship_processor.py b/src/chat/focus_chat/info_processors/relationship_processor.py index d4573fcad..e16def9fe 100644 --- a/src/chat/focus_chat/info_processors/relationship_processor.py +++ b/src/chat/focus_chat/info_processors/relationship_processor.py @@ -13,7 +13,6 @@ from typing import List from typing import Dict from src.chat.focus_chat.info.info_base import InfoBase from src.chat.focus_chat.info.relation_info import RelationInfo -from src.person_info.person_info import PersonInfoManager from json_repair import repair_json from src.person_info.person_info import get_person_info_manager import json @@ -26,7 +25,6 @@ from src.chat.utils.chat_message_builder import ( ) import os import pickle -import random # 消息段清理配置 @@ -446,8 +444,8 @@ class PersonImpressionpProcessor(BaseProcessor): List[InfoBase]: 处理后的结构化信息列表 """ await self.build_relation(observations) - - relation_info_str = await self.relation_identify(observations,action_type,action_data) + + relation_info_str = await self.relation_identify(observations, action_type, action_data) if relation_info_str: relation_info = RelationInfo() @@ -462,7 +460,7 @@ class PersonImpressionpProcessor(BaseProcessor): """构建关系""" self._cleanup_old_segments() current_time = time.time() - + if observations: for observation in observations: if isinstance(observation, ChattingObservation): @@ -518,7 +516,7 @@ class PersonImpressionpProcessor(BaseProcessor): # 移除已处理的用户缓存 del self.person_engaged_cache[person_id] self._save_cache() - + async def relation_identify( self, observations: List[Observation] = None, @@ -527,7 +525,7 @@ class PersonImpressionpProcessor(BaseProcessor): ): """ 从人物获取信息 - """ + """ chat_observe_info = "" current_time = time.time() @@ -567,7 +565,6 @@ class PersonImpressionpProcessor(BaseProcessor): self.last_processed_message_time = max(self.last_processed_message_time, msg_time) break - for person_id in list(self.info_fetched_cache.keys()): for info_type in list(self.info_fetched_cache[person_id].keys()): self.info_fetched_cache[person_id][info_type]["ttl"] -= 1 @@ -575,11 +572,7 @@ class PersonImpressionpProcessor(BaseProcessor): del self.info_fetched_cache[person_id][info_type] if not self.info_fetched_cache[person_id]: del self.info_fetched_cache[person_id] - - - - if action_type != "reply": return None @@ -831,7 +824,6 @@ class PersonImpressionpProcessor(BaseProcessor): logger.info(f"{self.log_prefix} 记得 {person_name} 的 {info_type}: {cached_info}") return - try: person_name = await person_info_manager.get_value(person_id, "person_name") person_impression = await person_info_manager.get_value(person_id, "impression") @@ -864,9 +856,7 @@ class PersonImpressionpProcessor(BaseProcessor): return nickname_str = ",".join(global_config.bot.alias_names) - name_block = ( - f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" - ) + name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format( name_block=name_block, info_type=info_type, diff --git a/src/chat/focus_chat/info_processors/tool_processor.py b/src/chat/focus_chat/info_processors/tool_processor.py index 51bc4529e..f0034af1d 100644 --- a/src/chat/focus_chat/info_processors/tool_processor.py +++ b/src/chat/focus_chat/info_processors/tool_processor.py @@ -8,7 +8,7 @@ from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.tools.tool_use import ToolUser from src.chat.utils.json_utils import process_llm_tool_calls from .base_processor import BaseProcessor -from typing import List, Optional +from typing import List from src.chat.heart_flow.observation.observation import Observation from src.chat.focus_chat.info.structured_info import StructuredInfo from src.chat.heart_flow.observation.structure_observation import StructureObservation @@ -92,9 +92,7 @@ class ToolProcessor(BaseProcessor): return [structured_info] - async def execute_tools( - self, observation: ChattingObservation, action_type: str = None, action_data: dict = None - ): + async def execute_tools(self, observation: ChattingObservation, action_type: str = None, action_data: dict = None): """ 并行执行工具,返回结构化信息