diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index efd0ea1ed..364303ccd 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -87,12 +87,12 @@ class InterestChatting: def add_interest_dict(self, message: MessageRecv, interest_value: float, is_mentioned: bool): """添加消息到兴趣字典 - + 参数: message: 接收到的消息 interest_value: 兴趣值 is_mentioned: 是否被提及 - + 功能: 1. 将消息添加到兴趣字典 2. 更新最后交互时间 @@ -101,7 +101,7 @@ class InterestChatting: # 添加新消息 self.interest_dict[message.message_info.message_id] = (message, interest_value, is_mentioned) self.last_interaction_time = time.time() - + # 如果字典长度超过10,删除最旧的消息 if len(self.interest_dict) > 10: oldest_key = next(iter(self.interest_dict)) diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index 62d9e2f7b..46e34d1d3 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -2,7 +2,7 @@ import asyncio import time import random from typing import Dict, Any, Optional, List -import json # 导入 json 模块 +import json # 导入 json 模块 # 导入日志模块 from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG @@ -407,13 +407,13 @@ class SubHeartflowManager: f"基于以上信息,该子心流是否表现出足够的活跃迹象或重要性," f"值得将其唤醒并进入常规聊天(CHAT)状态?\n" f"请以 JSON 格式回答,包含一个键 'decision',其值为 true 或 false.\n" - f"例如:{{\"decision\": true}}\n" + f'例如:{{"decision": true}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_activate = await self._llm_evaluate_state_transition(prompt) - if should_activate is None: # 处理解析失败或意外情况 + if should_activate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") continue @@ -445,13 +445,13 @@ class SubHeartflowManager: f"基于以上信息,该子心流是否表现出不活跃、对话结束或不再需要关注的迹象," f"应该让其进入休眠(ABSENT)状态?\n" f"请以 JSON 格式回答,包含一个键 'decision',其值为 true (表示应休眠) 或 false (表示不应休眠).\n" - f"例如:{{\"decision\": true}}\n" + f'例如:{{"decision": true}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_deactivate = await self._llm_evaluate_state_transition(prompt) - if should_deactivate is None: # 处理解析失败或意外情况 + if should_deactivate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") continue @@ -482,24 +482,28 @@ class SubHeartflowManager: try: # --- 真实的 LLM 调用 --- response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt) - logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: ```{response_text}```") + logger.debug( + f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: ```{response_text}```" + ) # --- 解析 JSON 响应 --- try: # 尝试去除可能的Markdown代码块标记 - cleaned_response = response_text.strip().strip('`').strip() - if cleaned_response.startswith('json'): + cleaned_response = response_text.strip().strip("`").strip() + if cleaned_response.startswith("json"): cleaned_response = cleaned_response[4:].strip() data = json.loads(cleaned_response) - decision = data.get("decision") # 使用 .get() 避免 KeyError + decision = data.get("decision") # 使用 .get() 避免 KeyError if isinstance(decision, bool): logger.debug(f"{log_prefix} LLM评估结果 (来自JSON): {'建议转换' if decision else '建议不转换'}") return decision else: - logger.warning(f"{log_prefix} LLM 返回的 JSON 中 'decision' 键的值不是布尔型: {decision}。响应: {response_text}") - return None # 值类型不正确 + logger.warning( + f"{log_prefix} LLM 返回的 JSON 中 'decision' 键的值不是布尔型: {decision}。响应: {response_text}" + ) + return None # 值类型不正确 except json.JSONDecodeError as json_err: logger.warning(f"{log_prefix} LLM 返回的响应不是有效的 JSON: {json_err}。响应: {response_text}") @@ -510,15 +514,15 @@ class SubHeartflowManager: if "false" in response_text.lower(): logger.debug(f"{log_prefix} 在非JSON响应中找到 'false',解释为建议不转换") return False - return None # JSON 解析失败,也未找到关键词 - except Exception as parse_err: # 捕获其他可能的解析错误 + return None # JSON 解析失败,也未找到关键词 + except Exception as parse_err: # 捕获其他可能的解析错误 logger.warning(f"{log_prefix} 解析 LLM JSON 响应时发生意外错误: {parse_err}。响应: {response_text}") return None except Exception as e: logger.error(f"{log_prefix} 调用 LLM 或处理其响应时出错: {e}", exc_info=True) traceback.print_exc() - return None # LLM 调用或处理失败 + return None # LLM 调用或处理失败 def count_subflows_by_state(self, state: ChatState) -> int: """统计指定状态的子心流数量""" diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index d7be9bef0..912da3520 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -48,7 +48,7 @@ class NormalChat: self.mood_manager = MoodManager.get_instance() # MoodManager 保持单例 # 存储此实例的兴趣监控任务 self.start_time = time.time() - + self._chat_task: Optional[asyncio.Task] = None logger.info(f"[{self.stream_name}] NormalChat 实例初始化完成。") @@ -325,12 +325,12 @@ class NormalChat: """处理启动时存在于 interest_dict 中的高兴趣消息。""" items_to_process = list(self.interest_dict.items()) if not items_to_process: - return # 没有初始消息,直接返回 + return # 没有初始消息,直接返回 logger.info(f"[{self.stream_name}] 发现 {len(items_to_process)} 条初始兴趣消息,开始处理高兴趣部分...") - interest_values = [item[1][1] for item in items_to_process] # 提取兴趣值列表 + interest_values = [item[1][1] for item in items_to_process] # 提取兴趣值列表 - messages_to_reply = [] # 需要立即回复的消息 + messages_to_reply = [] # 需要立即回复的消息 if len(interest_values) == 1: # 如果只有一个消息,直接处理 @@ -342,7 +342,9 @@ class NormalChat: mean_interest = statistics.mean(interest_values) stdev_interest = statistics.stdev(interest_values) threshold = mean_interest + stdev_interest - logger.info(f"[{self.stream_name}] 初始兴趣值 均值: {mean_interest:.2f}, 标准差: {stdev_interest:.2f}, 阈值: {threshold:.2f}") + logger.info( + f"[{self.stream_name}] 初始兴趣值 均值: {mean_interest:.2f}, 标准差: {stdev_interest:.2f}, 阈值: {threshold:.2f}" + ) # 找出高于阈值的消息 for item in items_to_process: @@ -351,7 +353,7 @@ class NormalChat: messages_to_reply.append(item) logger.info(f"[{self.stream_name}] 找到 {len(messages_to_reply)} 条高于阈值的初始消息进行处理。") except statistics.StatisticsError as e: - logger.error(f"[{self.stream_name}] 计算初始兴趣统计值时出错: {e},跳过初始处理。") + logger.error(f"[{self.stream_name}] 计算初始兴趣统计值时出错: {e},跳过初始处理。") # 处理需要回复的消息 processed_count = 0 @@ -359,18 +361,18 @@ class NormalChat: msg_id, (message, interest_value, is_mentioned) = item try: logger.info(f"[{self.stream_name}] 处理初始高兴趣消息 {msg_id} (兴趣值: {interest_value:.2f})") - await self.normal_response( - message=message, is_mentioned=is_mentioned, interested_rate=interest_value - ) + await self.normal_response(message=message, is_mentioned=is_mentioned, interested_rate=interest_value) processed_count += 1 except Exception as e: logger.error(f"[{self.stream_name}] 处理初始兴趣消息 {msg_id} 时出错: {e}\n{traceback.format_exc()}") finally: # 无论成功与否都清空兴趣字典 self.interest_dict.clear() - - logger.info(f"[{self.stream_name}] 初始高兴趣消息处理完毕,共处理 {processed_count} 条。剩余 {len(self.interest_dict)} 条待轮询。") + logger.info( + f"[{self.stream_name}] 初始高兴趣消息处理完毕,共处理 {processed_count} 条。剩余 {len(self.interest_dict)} 条待轮询。" + ) + # --- 新增结束 --- # 保持 staticmethod, 因为不依赖实例状态, 但需要 chat 对象来获取日志上下文