diff --git a/changelogs/changelog.md b/changelogs/changelog.md index e092b3d49..a6bc170b1 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -1,7 +1,7 @@ # Changelog ## [0.8.0] - 2025-1-6 -重大升级!插件系统全面重构,表达方式系统大幅优化 +重大升级!插件系统全面重构,表达方式系统大幅优化,focus大幅降低token花费和反应速度,加入了人物印象系统,麦麦可以记住群友的特点。支持更精细的分群聊天频率控制,normal模式可以使用planner和action MaiBot 0.8.0 重磅升级!插件系统全面重构,支持更强大的扩展能力;表达方式系统大幅优化,支持智能学习和衰减机制;聊天频率控制更加精细,支持时段化管理;HFC系统性能大幅提升,处理器后置化减少消耗;关系系统升级支持即时构建和人物侧写;日志系统重构使用structlog;大量稳定性修复和性能优化。 diff --git a/scripts/analyze_expressions.py b/scripts/analyze_expressions.py index 0cda31a06..93e7cb1a0 100644 --- a/scripts/analyze_expressions.py +++ b/scripts/analyze_expressions.py @@ -213,3 +213,4 @@ def analyze_expressions(): if __name__ == "__main__": analyze_expressions() + diff --git a/scripts/analyze_group_similarity.py b/scripts/analyze_group_similarity.py index f1d53ee20..686d594e0 100644 --- a/scripts/analyze_group_similarity.py +++ b/scripts/analyze_group_similarity.py @@ -194,3 +194,4 @@ def analyze_group_similarity(): if __name__ == "__main__": analyze_group_similarity() + diff --git a/src/chat/express/expression_selector.py b/src/chat/express/expression_selector.py index aecc46a91..272e3e06b 100644 --- a/src/chat/express/expression_selector.py +++ b/src/chat/express/expression_selector.py @@ -148,7 +148,7 @@ class ExpressionSelector: expr["count"] = new_count expr["last_active_time"] = time.time() - # logger.info(f"表达方式激活: 原count={current_count:.2f}, 增量={increment}, 新count={new_count:.2f}") + logger.info(f"表达方式激活: 原count={current_count:.3f}, 增量={increment}, 新count={new_count:.3f}") break # 保存更新后的文件 @@ -238,7 +238,7 @@ class ExpressionSelector: valid_expressions.append(expression) # 对选中的表达方式count数+0.1 - self.update_expression_count(chat_id, expression, 0.0001) + self.update_expression_count(chat_id, expression, 0.001) # logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个") return valid_expressions diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 9bbb3e67e..f3bcd17e0 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -112,6 +112,13 @@ class HeartFChatting: self.memory_activator = MemoryActivator() + # 新增:消息计数器和疲惫阈值 + self._message_count = 0 # 发送的消息计数 + # 基于exit_focus_threshold动态计算疲惫阈值 + # 基础值30条,通过exit_focus_threshold调节:threshold越小,越容易疲惫 + self._message_threshold = max(10, int(30 * global_config.chat.exit_focus_threshold)) + self._fatigue_triggered = False # 是否已触发疲惫退出 + # 初始化观察器 self.observations: List[Observation] = [] self._register_observations() @@ -177,6 +184,8 @@ class HeartFChatting: actual_version = performance_version or get_hfc_version() self.performance_logger = HFCPerformanceLogger(chat_id, actual_version) + logger.info(f"{self.log_prefix} HeartFChatting 初始化完成,消息疲惫阈值: {self._message_threshold}条(基于exit_focus_threshold={global_config.chat.exit_focus_threshold}计算,仅在auto模式下生效)") + def _register_observations(self): """注册所有观察器""" self.observations = [] # 清空已有的 @@ -289,6 +298,9 @@ class HeartFChatting: return try: + # 重置消息计数器,开始新的focus会话 + self.reset_message_count() + # 标记为活动状态,防止重复启动 self._loop_active = True @@ -1164,6 +1176,24 @@ class HeartFChatting: command = action_data["_system_command"] logger.debug(f"{self.log_prefix} 从action_data中获取系统命令: {command}") + # 新增:消息计数和疲惫检查 + if action == "reply" and success: + self._message_count += 1 + current_threshold = self._get_current_fatigue_threshold() + logger.info(f"{self.log_prefix} 已发送第 {self._message_count} 条消息(动态阈值: {current_threshold}, exit_focus_threshold: {global_config.chat.exit_focus_threshold})") + + # 检查是否达到疲惫阈值(只有在auto模式下才会自动退出) + if (global_config.chat.chat_mode == "auto" and + self._message_count >= current_threshold and + not self._fatigue_triggered): + self._fatigue_triggered = True + logger.info(f"{self.log_prefix} [auto模式] 已发送 {self._message_count} 条消息,达到疲惫阈值 {current_threshold},麦麦感到疲惫了,准备退出专注聊天模式") + # 设置系统命令,在下次循环检查时触发退出 + command = "stop_focus_chat" + elif (self._message_count >= current_threshold and + global_config.chat.chat_mode != "auto"): + logger.info(f"{self.log_prefix} [非auto模式] 已发送 {self._message_count} 条消息,达到疲惫阈值 {current_threshold},但非auto模式不会自动退出") + logger.debug(f"{self.log_prefix} 麦麦执行了'{action}', 返回结果'{success}', '{reply_text}', '{command}'") return success, reply_text, command @@ -1173,11 +1203,45 @@ class HeartFChatting: traceback.print_exc() return False, "", "" + def _get_current_fatigue_threshold(self) -> int: + """动态获取当前的疲惫阈值,基于exit_focus_threshold配置 + + Returns: + int: 当前的疲惫阈值 + """ + return max(10, int(30 / global_config.chat.exit_focus_threshold)) + + def get_message_count_info(self) -> dict: + """获取消息计数信息 + + Returns: + dict: 包含消息计数信息的字典 + """ + current_threshold = self._get_current_fatigue_threshold() + return { + "current_count": self._message_count, + "threshold": current_threshold, + "fatigue_triggered": self._fatigue_triggered, + "remaining": max(0, current_threshold - self._message_count) + } + + def reset_message_count(self): + """重置消息计数器(用于重新启动focus模式时)""" + self._message_count = 0 + self._fatigue_triggered = False + logger.info(f"{self.log_prefix} 消息计数器已重置") + async def shutdown(self): """优雅关闭HeartFChatting实例,取消活动循环任务""" logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...") self._shutting_down = True # <-- 在开始关闭时设置标志位 + # 记录最终的消息统计 + if self._message_count > 0: + logger.info(f"{self.log_prefix} 本次focus会话共发送了 {self._message_count} 条消息") + if self._fatigue_triggered: + logger.info(f"{self.log_prefix} 因疲惫而退出focus模式") + # 取消循环任务 if self._loop_task and not self._loop_task.done(): logger.info(f"{self.log_prefix} 正在取消HeartFChatting循环任务") @@ -1206,6 +1270,9 @@ class HeartFChatting: except Exception as e: logger.warning(f"{self.log_prefix} 完成性能统计时出错: {e}") + # 重置消息计数器,为下次启动做准备 + self.reset_message_count() + logger.info(f"{self.log_prefix} HeartFChatting关闭完成") def get_cycle_history(self, last_n: Optional[int] = None) -> List[Dict[str, Any]]: diff --git a/src/plugins/built_in/core_actions/no_reply.py b/src/plugins/built_in/core_actions/no_reply.py index 4929615f1..c38adb83e 100644 --- a/src/plugins/built_in/core_actions/no_reply.py +++ b/src/plugins/built_in/core_actions/no_reply.py @@ -327,7 +327,7 @@ class NoReplyAction(BaseAction): # 使用 utils_small 模型 small_model = getattr(available_models, "utils_small", None) - print(judge_prompt) + logger.debug(judge_prompt) if small_model: # 使用小模型进行判断 diff --git a/src/plugins/built_in/core_actions/plugin.py b/src/plugins/built_in/core_actions/plugin.py index c6592a7c5..dcd4ce5cf 100644 --- a/src/plugins/built_in/core_actions/plugin.py +++ b/src/plugins/built_in/core_actions/plugin.py @@ -117,7 +117,7 @@ class EmojiAction(BaseAction): normal_activation_type = ActionActivationType.RANDOM mode_enable = ChatMode.ALL parallel_action = True - random_activation_probability = 0.1 # 默认值,可通过配置覆盖 + random_activation_probability = 0.2 # 默认值,可通过配置覆盖 # 动作基本信息 action_name = "emoji" diff --git a/src/plugins/built_in/mute_plugin/plugin.py b/src/plugins/built_in/mute_plugin/plugin.py index 71e2f29c5..bbc44a9fa 100644 --- a/src/plugins/built_in/mute_plugin/plugin.py +++ b/src/plugins/built_in/mute_plugin/plugin.py @@ -115,7 +115,7 @@ class MuteAction(BaseAction): if allowed_group == current_group_key: logger.info(f"{self.log_prefix} 群组 {current_group_key} 有禁言动作权限") return True, None - + logger.warning(f"{self.log_prefix} 群组 {current_group_key} 没有禁言动作权限") return False, "当前群组没有使用禁言动作的权限" @@ -125,10 +125,6 @@ class MuteAction(BaseAction): # 首先检查群组权限 has_permission, permission_error = self._check_group_permission() - if not has_permission: - logger.error(f"{self.log_prefix} 权限检查失败: {permission_error}") - # 不发送错误消息,静默拒绝 - return False, permission_error # 获取参数 target = self.action_data.get("target") @@ -190,6 +186,32 @@ class MuteAction(BaseAction): # 获取模板化消息 message = self._get_template_message(target, time_str, reason) + + if not has_permission: + logger.warning(f"{self.log_prefix} 权限检查失败: {permission_error}") + result_status, result_message = await generator_api.rewrite_reply( + chat_stream=self.chat_stream, + reply_data={ + "raw_reply": "我想禁言{target},但是我没有权限", + "reason": "表达自己没有在这个群禁言的能力", + }, + ) + + if result_status: + for reply_seg in result_message: + data = reply_seg[1] + await self.send_text(data) + + await self.store_action_info( + action_build_into_prompt=True, + action_prompt_display=f"尝试禁言了用户 {target},但是没有权限,无法禁言", + action_done=True, + ) + + + + # 不发送错误消息,静默拒绝 + return False, permission_error result_status, result_message = await generator_api.rewrite_reply( chat_stream=self.chat_stream,