From 3ddd55e387069fb6a32b69ce17ce02003e8ac9cb Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sat, 26 Apr 2025 15:23:16 +0800 Subject: [PATCH 1/8] =?UTF-8?q?feat:=E6=8A=8ACHAT=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E4=BA=A4=E7=BB=99LLM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interest_monitor_gui.py | 2 +- src/heart_flow/README.md | 7 +- src/heart_flow/background_tasks.py | 33 ++- src/heart_flow/heartflow.py | 1 - src/heart_flow/interest_logger.py | 2 +- src/heart_flow/sub_heartflow.py | 2 +- src/heart_flow/subheartflow_manager.py | 261 +++++++++++++----- .../heartFC_chat/heartflow_processor.py | 2 +- 8 files changed, 218 insertions(+), 92 deletions(-) diff --git a/interest_monitor_gui.py b/interest_monitor_gui.py index 245a0ae9..fb9e51cf 100644 --- a/interest_monitor_gui.py +++ b/interest_monitor_gui.py @@ -247,7 +247,7 @@ class InterestMonitorApp: self.stream_chat_states[stream_id] = subflow_entry.get("sub_chat_state", "N/A") self.stream_threshold_status[stream_id] = subflow_entry.get("is_above_threshold", False) self.stream_last_active[stream_id] = subflow_entry.get( - "last_changed_state_time" + "chat_state_changed_time" ) # 存储原始时间戳 self.stream_last_interaction[stream_id] = subflow_entry.get( "last_interaction_time" diff --git a/src/heart_flow/README.md b/src/heart_flow/README.md index 24d094cc..a2540ebf 100644 --- a/src/heart_flow/README.md +++ b/src/heart_flow/README.md @@ -105,7 +105,8 @@ c HeartFChatting工作方式 - 负责所有 `SubHeartflow` 实例的生命周期管理,包括: - 创建和获取 (`get_or_create_subheartflow`)。 - 停止和清理 (`sleep_subheartflow`, `cleanup_inactive_subheartflows`)。 - - 根据 `Heartflow` 的状态 (`self.mai_state_info`) 和限制条件,激活、停用或调整子心流的状态(例如 `enforce_subheartflow_limits`, `activate_random_subflows_to_chat`, `evaluate_interest_and_promote`)。 + - 根据 `Heartflow` 的状态 (`self.mai_state_info`) 和限制条件,激活、停用或调整子心流的状态(例如 `enforce_subheartflow_limits`, `randomly_deactivate_subflows`, `evaluate_interest_and_promote`)。 + - **新增**: 通过调用 `evaluate_and_transition_subflows_by_llm` 方法,使用 LLM (配置与 `Heartflow` 主 LLM 相同) 评估处于 `ABSENT` 或 `CHAT` 状态的子心流,根据观察到的活动摘要和 `Heartflow` 的当前状态,判断是否应在 `ABSENT` 和 `CHAT` 之间进行转换 (同样受限于 `CHAT` 状态的数量上限)。 - **清理机制**: 通过后台任务 (`BackgroundTaskManager`) 定期调用 `cleanup_inactive_subheartflows` 方法,此方法会识别并**删除**那些处于 `ABSENT` 状态超过一小时 (`INACTIVE_THRESHOLD_SECONDS`) 的子心流实例。 ### 1.5. 消息处理与回复流程 (Message Processing vs. Replying Flow) @@ -149,9 +150,9 @@ c HeartFChatting工作方式 * `ChatState.FOCUSED` (专注/认真水群): 专注聊天模式。激活 `HeartFlowChatInstance`。 - **选择**: 子心流可以根据外部指令(来自 `SubHeartflowManager`)或内部逻辑(未来的扩展)选择进入 `ABSENT` 状态(不回复不观察),或进入 `CHAT` / `FOCUSED` 中的一种回复模式。 - **状态转换机制** (由 `SubHeartflowManager` 驱动): - - **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制(通过 `self.mai_state_info` 获取),选择部分 `ABSENT` 状态的子心流,**检查当前 CHAT 状态数量是否达到上限**,如果未达上限,则调用其 `change_chat_state` 方法将其转换为 `CHAT`。 + - **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制(通过 `self.mai_state_info` 获取),选择部分 `ABSENT` 状态的子心流,**检查当前 CHAT 状态数量是否达到上限**,如果未达上限,则调用其 `change_chat_state` 方法将其转换为 `CHAT`。此外,`evaluate_and_transition_subflows_by_llm` 方法也会根据 LLM 的判断,在未达上限时将 `ABSENT` 状态的子心流激活为 `CHAT`。 - **激活 `FOCUSED`**: `SubHeartflowManager` 会定期评估处于 `CHAT` 状态的子心流的兴趣度 (`InterestChatting.start_hfc_probability`),若满足条件且**检查当前 FOCUSED 状态数量未达上限**(通过 `self.mai_state_info` 获取限制),则调用 `change_chat_state` 将其提升为 `FOCUSED`。 - - **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃或随机概率等原因,调用 `change_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。当子心流进入 `ABSENT` 状态后,如果持续一小时不活跃,才会被后台清理任务删除。 + - **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃、随机概率 (`randomly_deactivate_subflows`) 或 LLM 评估 (`evaluate_and_transition_subflows_by_llm` 判断 `CHAT` 状态子心流应休眠) 等原因,调用 `change_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。当子心流进入 `ABSENT` 状态后,如果持续一小时不活跃,才会被后台清理任务删除。 - **注意**: `change_chat_state` 方法本身只负责执行状态转换和管理内部聊天实例(`NormalChatInstance`/`HeartFlowChatInstance`),不再进行限额检查。限额检查的责任完全由调用方(即 `SubHeartflowManager` 中的相关方法,这些方法会使用内部存储的 `mai_state_info` 来获取限制)承担。 ## 3. 聊天实例详解 (Chat Instances Explained) diff --git a/src/heart_flow/background_tasks.py b/src/heart_flow/background_tasks.py index 85b77579..a1a22668 100644 --- a/src/heart_flow/background_tasks.py +++ b/src/heart_flow/background_tasks.py @@ -34,7 +34,6 @@ class BackgroundTaskManager: update_interval: int, cleanup_interval: int, log_interval: int, - inactive_threshold: int, # 新增兴趣评估间隔参数 interest_eval_interval: int = INTEREST_EVAL_INTERVAL_SECONDS, # 新增随机停用间隔参数 @@ -58,6 +57,7 @@ class BackgroundTaskManager: self._logging_task: Optional[asyncio.Task] = None self._interest_eval_task: Optional[asyncio.Task] = None # 新增兴趣评估任务引用 self._random_deactivation_task: Optional[asyncio.Task] = None # 新增随机停用任务引用 + self._hf_judge_state_update_task: Optional[asyncio.Task] = None # 新增状态评估任务引用 self._tasks: List[Optional[asyncio.Task]] = [] # Keep track of all tasks async def start_tasks(self): @@ -79,12 +79,20 @@ class BackgroundTaskManager: f"聊天状态更新任务已启动 间隔:{self.update_interval}s", "_state_update_task", ), + ( + self._hf_judge_state_update_task, + lambda: self._run_hf_judge_state_update_cycle(300), + "hf_judge_state_update", + "debug", + f"状态评估任务已启动 间隔:{300}s", + "_hf_judge_state_update_task", + ), ( self._cleanup_task, self._run_cleanup_cycle, "hf_cleanup", "info", - f"清理任务已启动 间隔:{self.cleanup_interval}s 阈值:{self.inactive_threshold}s", + f"清理任务已启动 间隔:{self.cleanup_interval}s", "_cleanup_task", ), ( @@ -203,21 +211,21 @@ class BackgroundTaskManager: if state_changed: current_state = self.mai_state_info.get_current_state() - await self.subheartflow_manager.enforce_subheartflow_limits(current_state) + await self.subheartflow_manager.enforce_subheartflow_limits() # 状态转换处理 + if ( - previous_status == self.mai_state_info.mai_status.OFFLINE - and current_state != self.mai_state_info.mai_status.OFFLINE - ): - logger.info("[后台任务] 主状态激活,触发子流激活") - await self.subheartflow_manager.activate_random_subflows_to_chat(current_state) - elif ( current_state == self.mai_state_info.mai_status.OFFLINE and previous_status != self.mai_state_info.mai_status.OFFLINE ): logger.info("检测到离线,停用所有子心流") await self.subheartflow_manager.deactivate_all_subflows() + + async def _perform_hf_judge_state_update_work(self): + """调用llm检测是否转换ABSENT-CHAT状态""" + logger.info("[状态评估任务] 开始基于LLM评估子心流状态...") + await self.subheartflow_manager.evaluate_and_transition_subflows_by_llm() async def _perform_cleanup_work(self): """执行子心流清理任务 @@ -252,7 +260,7 @@ class BackgroundTaskManager: async def _perform_interest_eval_work(self): """执行一轮子心流兴趣评估与提升检查。""" # 直接调用 subheartflow_manager 的方法,并传递当前状态信息 - await self.subheartflow_manager.evaluate_interest_and_promote(self.mai_state_info) + await self.subheartflow_manager.evaluate_interest_and_promote() # --- 结束新增 --- @@ -268,6 +276,11 @@ class BackgroundTaskManager: await self._run_periodic_loop( task_name="State Update", interval=interval, task_func=self._perform_state_update_work ) + + async def _run_hf_judge_state_update_cycle(self, interval: int): + await self._run_periodic_loop( + task_name="State Update", interval=interval, task_func=self._perform_hf_judge_state_update_work + ) async def _run_cleanup_cycle(self): await self._run_periodic_loop( diff --git a/src/heart_flow/heartflow.py b/src/heart_flow/heartflow.py index 7d92ae52..a0fb8e4f 100644 --- a/src/heart_flow/heartflow.py +++ b/src/heart_flow/heartflow.py @@ -72,7 +72,6 @@ class Heartflow: update_interval=STATE_UPDATE_INTERVAL_SECONDS, cleanup_interval=CLEANUP_INTERVAL_SECONDS, log_interval=3, # Example: Using value directly, ideally get from config - inactive_threshold=INACTIVE_THRESHOLD_SECONDS, ) async def get_or_create_subheartflow(self, subheartflow_id: Any) -> Optional["SubHeartflow"]: diff --git a/src/heart_flow/interest_logger.py b/src/heart_flow/interest_logger.py index 7802f87b..d4e746e6 100644 --- a/src/heart_flow/interest_logger.py +++ b/src/heart_flow/interest_logger.py @@ -58,7 +58,7 @@ class InterestLogger: return results for subheartflow in all_flows: - if self.subheartflow_manager.get_or_create_subheartflow(subheartflow.subheartflow_id): + if await self.subheartflow_manager.get_or_create_subheartflow(subheartflow.subheartflow_id): tasks.append( asyncio.create_task(subheartflow.get_full_state(), name=f"get_state_{subheartflow.subheartflow_id}") ) diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index 9cbd7b3a..33218f5f 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -481,7 +481,7 @@ class SubHeartflow: "interest_state": interest_state, "current_mind": self.sub_mind.current_mind, "chat_state": self.chat_state.chat_status.value, - "last_changed_state_time": self.last_changed_state_time, + "chat_state_changed_time": self.chat_state_changed_time, } async def shutdown(self): diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index cd32136a..33fdae4e 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -12,7 +12,11 @@ from src.plugins.chat.chat_stream import chat_manager # 导入心流相关类 from src.heart_flow.sub_heartflow import SubHeartflow, ChatState from src.heart_flow.mai_state_manager import MaiStateInfo -from .observation import ChattingObservation +from .observation import ChattingObservation, Observation + +# 导入LLM请求工具 +from src.plugins.models.utils_model import LLMRequest +from src.config.config import global_config # 初始化日志记录器 @@ -34,6 +38,15 @@ class SubHeartflowManager: self._lock = asyncio.Lock() # 用于保护 self.subheartflows 的访问 self.mai_state_info: MaiStateInfo = mai_state_info # 存储传入的 MaiStateInfo 实例 + # 为 LLM 状态评估创建一个 LLMRequest 实例 + # 使用与 Heartflow 相同的模型和参数 + self.llm_state_evaluator = LLMRequest( + model=global_config.llm_heartflow, # 与 Heartflow 一致 + temperature=0.6, # 与 Heartflow 一致 + max_tokens=1000, # 与 Heartflow 一致 (虽然可能不需要这么多) + request_type="subheartflow_state_eval" # 保留特定的请求类型 + ) + def get_all_subheartflows(self) -> List["SubHeartflow"]: """获取所有当前管理的 SubHeartflow 实例列表 (快照)。""" return list(self.subheartflows.values()) @@ -103,24 +116,6 @@ class SubHeartflowManager: except Exception as e: logger.error(f"[子心流管理] 设置ABSENT状态失败: {e}") - # 停止子心流内部循环 - subheartflow.should_stop = True - - # 取消后台任务 - task = subheartflow.task - if task and not task.done(): - task.cancel() - logger.debug(f"[子心流管理] 已取消 {stream_name} 的后台任务") - - # 从管理字典中移除 - if subheartflow_id in self.subheartflows: - del self.subheartflows[subheartflow_id] - logger.debug(f"[子心流管理] 已移除 {stream_name}") - return True - else: - logger.warning(f"[子心流管理] {stream_name} 已被提前移除") - return False - def get_inactive_subheartflows(self, max_age_seconds=INACTIVE_THRESHOLD_SECONDS): """识别并返回需要清理的不活跃(处于ABSENT状态超过一小时)子心流(id, 原因)""" current_time = time.time() @@ -185,52 +180,6 @@ class SubHeartflowManager: else: logger.debug(f"[限制] 无需停止, 当前总数:{len(self.subheartflows)}") - async def activate_random_subflows_to_chat(self): - """主状态激活时,随机选择ABSENT子心流进入CHAT状态""" - # 使用 self.mai_state_info 获取当前状态和限制 - current_mai_state = self.mai_state_info.get_current_state() - limit = current_mai_state.get_normal_chat_max_num() - if limit <= 0: - logger.info("[激活] 当前状态不允许CHAT子心流") - return - - # 获取所有ABSENT状态的子心流 - absent_flows = [flow for flow in self.subheartflows.values() if flow.chat_state.chat_status == ChatState.ABSENT] - - num_to_activate = min(limit, len(absent_flows)) - if num_to_activate <= 0: - logger.info(f"[激活] 无可用ABSENT子心流(限额:{limit}, 可用:{len(absent_flows)})") - return - - logger.info(f"[激活] 随机选择{num_to_activate}个ABSENT子心流进入CHAT状态") - activated_count = 0 - - for flow in random.sample(absent_flows, num_to_activate): - flow_id = flow.subheartflow_id - stream_name = chat_manager.get_stream_name(flow_id) or flow_id - - if flow_id not in self.subheartflows: - logger.warning(f"[激活] 跳过{stream_name}, 子心流已不存在") - continue - - logger.debug(f"[激活] 正在激活子心流{stream_name}") - - # --- 限额检查 --- # - current_chat_count = self.count_subflows_by_state(ChatState.CHAT) - if current_chat_count >= limit: - logger.warning(f"[激活] 跳过{stream_name}, 普通聊天已达上限 ({current_chat_count}/{limit})") - continue # 跳过此子心流,继续尝试激活下一个 - # --- 结束限额检查 --- # - - # 移除 states_num 参数 - await flow.change_chat_state(ChatState.CHAT) - - if flow.chat_state.chat_status == ChatState.CHAT: - activated_count += 1 - else: - logger.warning(f"[激活] {stream_name}状态设置失败") - - logger.info(f"[激活] 完成, 成功激活{activated_count}个子心流") async def deactivate_all_subflows(self): """将所有子心流的状态更改为 ABSENT (例如主状态变为OFFLINE时调用)""" @@ -394,15 +343,172 @@ class SubHeartflowManager: else: logger.debug(f"{log_prefix_manager} 随机停用周期结束, 未停用任何子心流。") - def count_subflows_by_state(self, state: ChatState) -> int: - """统计指定状态的子心流数量 + + async def evaluate_and_transition_subflows_by_llm(self): + """ + 使用LLM评估每个子心流的状态,并根据LLM的判断执行状态转换(ABSENT <-> CHAT)。 + 注意:此函数包含对假设的LLM函数的调用。 + """ + log_prefix = "[LLM状态评估]" + logger.info(f"{log_prefix} 开始基于LLM评估子心流状态...") + + # 获取当前状态和限制,用于CHAT激活检查 + current_mai_state = self.mai_state_info.get_current_state() + chat_limit = current_mai_state.get_normal_chat_max_num() + + transitioned_to_chat = 0 + transitioned_to_absent = 0 + + async with self._lock: # 在锁内获取快照并迭代 + subflows_snapshot = list(self.subheartflows.values()) + # 使用不上锁的版本,因为我们已经在锁内 + current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT) + + if not subflows_snapshot: + logger.info(f"{log_prefix} 当前没有子心流需要评估。") + return + + for sub_hf in subflows_snapshot: + flow_id = sub_hf.subheartflow_id + stream_name = chat_manager.get_stream_name(flow_id) or flow_id + current_subflow_state = sub_hf.chat_state.chat_status + + # --- 获取观察内容 --- + # 从 sub_hf.observations 获取 ChattingObservation 并提取信息 + observation_summary = "没有可用的观察信息。" # 默认值 + try: + # 检查 observations 列表是否存在且不为空 + + # 假设第一个观察者是 ChattingObservation + first_observation = sub_hf.observations[0] + if isinstance(first_observation, ChattingObservation): + # 组合中期记忆和当前聊天内容 + current_chat = first_observation.talking_message_str or "当前无聊天内容。" + combined_summary = f"当前聊天内容:\n{current_chat}" + else: + logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。") + + + except Exception as e: + logger.warning(f"{log_prefix} [{stream_name}] 获取观察信息失败: {e}", exc_info=True) + # 保留默认值或错误信息 + combined_summary = f"获取观察信息时出错: {e}" + + + # --- 获取麦麦状态 --- + mai_state_description = f"麦麦当前状态: {current_mai_state.value}。" + + # --- 针对 ABSENT 状态 --- + if current_subflow_state == ChatState.ABSENT: + # 构建Prompt + prompt = ( + f"子心流 [{stream_name}] 当前处于非活跃(ABSENT)状态。\n" + f"{mai_state_description}\n" + f"最近观察到的内容摘要:\n---\n{combined_summary}\n---\n" + f"基于以上信息,该子心流是否表现出足够的活跃迹象或重要性," + f"值得将其唤醒并进入常规聊天(CHAT)状态?" + f"请回答 '是' 或 '否'。" + ) + + # 调用LLM评估 + try: + # 使用 self._llm_evaluate_state_transition + should_activate = await self._llm_evaluate_state_transition(prompt) + if should_activate: + # 检查CHAT限额 + if current_chat_count < chat_limit: + logger.info(f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换...") + await sub_hf.change_chat_state(ChatState.CHAT) + if sub_hf.chat_state.chat_status == ChatState.CHAT: + transitioned_to_chat += 1 + current_chat_count += 1 # 更新计数器 + else: + logger.warning(f"{log_prefix} [{stream_name}] 尝试激活到CHAT失败。") + else: + logger.info(f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。") + except Exception as e: + logger.error(f"{log_prefix} [{stream_name}] LLM评估或状态转换(ABSENT->CHAT)时出错: {e}", exc_info=True) + + + # --- 针对 CHAT 状态 --- + elif current_subflow_state == ChatState.CHAT: + # 构建Prompt + prompt = ( + f"子心流 [{stream_name}] 当前处于常规聊天(CHAT)状态。\n" + f"{mai_state_description}\n" + f"最近观察到的内容摘要:\n---\n{combined_summary}\n---\n" + f"基于以上信息,该子心流是否表现出不活跃、对话结束或不再需要关注的迹象," + f"应该让其进入休眠(ABSENT)状态?" + f"请回答 '是' 或 '否'。" + ) + + # 调用LLM评估 + try: + # 使用 self._llm_evaluate_state_transition + should_deactivate = await self._llm_evaluate_state_transition(prompt) + if should_deactivate: + logger.info(f"{log_prefix} [{stream_name}] LLM建议进入ABSENT状态。正在尝试转换...") + await sub_hf.change_chat_state(ChatState.ABSENT) + if sub_hf.chat_state.chat_status == ChatState.ABSENT: + transitioned_to_absent += 1 + current_chat_count -= 1 # 更新计数器 + else: + logger.warning(f"{log_prefix} [{stream_name}] 尝试转换为ABSENT失败。") + except Exception as e: + logger.error(f"{log_prefix} [{stream_name}] LLM评估或状态转换(CHAT->ABSENT)时出错: {e}", exc_info=True) + + # 可以选择性地为 FOCUSED 状态添加评估逻辑,例如判断是否降级回 CHAT 或 ABSENT + + logger.info( + f"{log_prefix} LLM评估周期结束。" + f" 成功转换到CHAT: {transitioned_to_chat}." + f" 成功转换到ABSENT: {transitioned_to_absent}." + ) + + + async def _llm_evaluate_state_transition(self, prompt: str) -> bool: + """ + 使用 LLM 评估是否应进行状态转换。 Args: - state: 要统计的聊天状态枚举值 + prompt: 提供给 LLM 的提示信息。 Returns: - int: 处于该状态的子心流数量 + bool: True 表示应该转换,False 表示不应该转换。 """ + log_prefix = "[LLM状态评估]" + try: + # --- 真实的 LLM 调用 --- + response_text, _, model_name = await self.llm_state_evaluator.generate_response_async(prompt) + logger.debug(f"{log_prefix} 使用模型 {model_name} 评估,原始响应: {response_text}") + # 解析响应 - 这里需要根据你的LLM的确切输出来调整逻辑 + # 假设 LLM 会明确回答 "是" 或 "否" + if response_text and "是" in response_text.strip(): + logger.debug(f"{log_prefix} LLM评估结果: 建议转换 (响应包含 '是')") + return True + elif response_text and "否" in response_text.strip(): + logger.debug(f"{log_prefix} LLM评估结果: 建议不转换 (响应包含 '否')") + return False + else: + logger.warning(f"{log_prefix} LLM 未明确回答 '是' 或 '否',响应: {response_text}") + # 可以设定一个默认行为,例如默认不转换 + return False + # --- 真实的 LLM 调用结束 --- + + # # --- 占位符逻辑:随机返回 True/False --- + # # 请在接入真实 LLM 后移除此部分 + # await asyncio.sleep(0.1) # 模拟LLM调用延迟 + # result = random.choice([True, False]) + # logger.debug(f"{log_prefix} (占位符) LLM评估结果: {'建议转换' if result else '建议不转换'}") + # return result + # # --- 占位符逻辑结束 --- + + except Exception as e: + logger.error(f"{log_prefix} 调用 LLM 进行状态评估时出错: {e}", exc_info=True) + + + def count_subflows_by_state(self, state: ChatState) -> int: + """统计指定状态的子心流数量""" count = 0 # 遍历所有子心流实例 for subheartflow in self.subheartflows.values(): @@ -411,12 +517,19 @@ class SubHeartflowManager: count += 1 return count - def get_active_subflow_minds(self) -> List[str]: - """获取所有活跃(非ABSENT)子心流的当前想法 - - 返回: - List[str]: 包含所有活跃子心流当前想法的列表 + def count_subflows_by_state_nolock(self, state: ChatState) -> int: """ + 统计指定状态的子心流数量 (不上锁版本)。 + 警告:仅应在已持有 self._lock 的上下文中使用此方法。 + """ + count = 0 + for subheartflow in self.subheartflows.values(): + if subheartflow.chat_state.chat_status == state: + count += 1 + return count + + def get_active_subflow_minds(self) -> List[str]: + """获取所有活跃(非ABSENT)子心流的当前想法""" minds = [] for subheartflow in self.subheartflows.values(): # 检查子心流是否活跃(非ABSENT状态) diff --git a/src/plugins/heartFC_chat/heartflow_processor.py b/src/plugins/heartFC_chat/heartflow_processor.py index 1f771688..c907f98a 100644 --- a/src/plugins/heartFC_chat/heartflow_processor.py +++ b/src/plugins/heartFC_chat/heartflow_processor.py @@ -167,7 +167,7 @@ class HeartFCProcessor: # 6. 兴趣度计算与更新 interested_rate, is_mentioned = await self._calculate_interest(message) await subheartflow.interest_chatting.increase_interest(value=interested_rate) - await subheartflow.interest_chatting.add_interest_dict(message, interested_rate, is_mentioned) + subheartflow.interest_chatting.add_interest_dict(message, interested_rate, is_mentioned) # 7. 日志记录 mes_name = chat.group_info.group_name if chat.group_info else "私聊" From 5f4b38e4ddb359f2757505926bbfd8bfd3d7dd51 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 15:31:48 +0800 Subject: [PATCH 2/8] fix --- src/plugins/PFC/conversation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index dc1e6a34..83081e80 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -77,7 +77,7 @@ class Conversation: raise try: logger.info(f"为 {self.stream_id} 加载初始聊天记录...") - initial_messages = await get_raw_msg_before_timestamp_with_chat( # + initial_messages = get_raw_msg_before_timestamp_with_chat( # chat_id=self.stream_id, timestamp=time.time(), limit=30, # 加载最近30条作为初始上下文,可以调整 From e52959d838f29722798daf74931e631193fd88cc Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sat, 26 Apr 2025 15:40:12 +0800 Subject: [PATCH 3/8] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Dllm=E7=88=86=E7=82=B8?= =?UTF-8?q?=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/background_tasks.py | 10 ++-- src/heart_flow/subheartflow_manager.py | 64 +++++++++++------------- src/plugins/memory_system/Hippocampus.py | 6 +-- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/heart_flow/background_tasks.py b/src/heart_flow/background_tasks.py index a1a22668..7ae4b62f 100644 --- a/src/heart_flow/background_tasks.py +++ b/src/heart_flow/background_tasks.py @@ -57,7 +57,7 @@ class BackgroundTaskManager: self._logging_task: Optional[asyncio.Task] = None self._interest_eval_task: Optional[asyncio.Task] = None # 新增兴趣评估任务引用 self._random_deactivation_task: Optional[asyncio.Task] = None # 新增随机停用任务引用 - self._hf_judge_state_update_task: Optional[asyncio.Task] = None # 新增状态评估任务引用 + self._hf_judge_state_update_task: Optional[asyncio.Task] = None # 新增状态评估任务引用 self._tasks: List[Optional[asyncio.Task]] = [] # Keep track of all tasks async def start_tasks(self): @@ -81,10 +81,10 @@ class BackgroundTaskManager: ), ( self._hf_judge_state_update_task, - lambda: self._run_hf_judge_state_update_cycle(300), + lambda: self._run_hf_judge_state_update_cycle(60), "hf_judge_state_update", "debug", - f"状态评估任务已启动 间隔:{300}s", + f"状态评估任务已启动 间隔:{60}s", "_hf_judge_state_update_task", ), ( @@ -221,7 +221,7 @@ class BackgroundTaskManager: ): logger.info("检测到离线,停用所有子心流") await self.subheartflow_manager.deactivate_all_subflows() - + async def _perform_hf_judge_state_update_work(self): """调用llm检测是否转换ABSENT-CHAT状态""" logger.info("[状态评估任务] 开始基于LLM评估子心流状态...") @@ -276,7 +276,7 @@ class BackgroundTaskManager: await self._run_periodic_loop( task_name="State Update", interval=interval, task_func=self._perform_state_update_work ) - + async def _run_hf_judge_state_update_cycle(self, interval: int): await self._run_periodic_loop( task_name="State Update", interval=interval, task_func=self._perform_hf_judge_state_update_work diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index 33fdae4e..9357ff3b 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -12,12 +12,14 @@ from src.plugins.chat.chat_stream import chat_manager # 导入心流相关类 from src.heart_flow.sub_heartflow import SubHeartflow, ChatState from src.heart_flow.mai_state_manager import MaiStateInfo -from .observation import ChattingObservation, Observation +from .observation import ChattingObservation # 导入LLM请求工具 from src.plugins.models.utils_model import LLMRequest from src.config.config import global_config +import traceback + # 初始化日志记录器 subheartflow_manager_log_config = LogConfig( @@ -41,10 +43,10 @@ class SubHeartflowManager: # 为 LLM 状态评估创建一个 LLMRequest 实例 # 使用与 Heartflow 相同的模型和参数 self.llm_state_evaluator = LLMRequest( - model=global_config.llm_heartflow, # 与 Heartflow 一致 - temperature=0.6, # 与 Heartflow 一致 - max_tokens=1000, # 与 Heartflow 一致 (虽然可能不需要这么多) - request_type="subheartflow_state_eval" # 保留特定的请求类型 + model=global_config.llm_heartflow, # 与 Heartflow 一致 + temperature=0.6, # 与 Heartflow 一致 + max_tokens=1000, # 与 Heartflow 一致 (虽然可能不需要这么多) + request_type="subheartflow_state_eval", # 保留特定的请求类型 ) def get_all_subheartflows(self) -> List["SubHeartflow"]: @@ -87,7 +89,7 @@ class SubHeartflowManager: # 注册子心流 self.subheartflows[subheartflow_id] = new_subflow heartflow_name = chat_manager.get_stream_name(subheartflow_id) or subheartflow_id - logger.info(f"[{heartflow_name}] 开始看消息") + logger.info(f"[{heartflow_name}] 开始接收消息") # 启动后台任务 asyncio.create_task(new_subflow.subheartflow_start_working()) @@ -180,7 +182,6 @@ class SubHeartflowManager: else: logger.debug(f"[限制] 无需停止, 当前总数:{len(self.subheartflows)}") - async def deactivate_all_subflows(self): """将所有子心流的状态更改为 ABSENT (例如主状态变为OFFLINE时调用)""" # logger.info("[停用] 开始将所有子心流状态设置为 ABSENT") @@ -343,7 +344,6 @@ class SubHeartflowManager: else: logger.debug(f"{log_prefix_manager} 随机停用周期结束, 未停用任何子心流。") - async def evaluate_and_transition_subflows_by_llm(self): """ 使用LLM评估每个子心流的状态,并根据LLM的判断执行状态转换(ABSENT <-> CHAT)。 @@ -359,7 +359,7 @@ class SubHeartflowManager: transitioned_to_chat = 0 transitioned_to_absent = 0 - async with self._lock: # 在锁内获取快照并迭代 + async with self._lock: # 在锁内获取快照并迭代 subflows_snapshot = list(self.subheartflows.values()) # 使用不上锁的版本,因为我们已经在锁内 current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT) @@ -375,26 +375,24 @@ class SubHeartflowManager: # --- 获取观察内容 --- # 从 sub_hf.observations 获取 ChattingObservation 并提取信息 - observation_summary = "没有可用的观察信息。" # 默认值 + _observation_summary = "没有可用的观察信息。" # 默认值 try: # 检查 observations 列表是否存在且不为空 - # 假设第一个观察者是 ChattingObservation + # 假设第一个观察者是 ChattingObservation first_observation = sub_hf.observations[0] if isinstance(first_observation, ChattingObservation): # 组合中期记忆和当前聊天内容 current_chat = first_observation.talking_message_str or "当前无聊天内容。" combined_summary = f"当前聊天内容:\n{current_chat}" else: - logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。") - + logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。") except Exception as e: logger.warning(f"{log_prefix} [{stream_name}] 获取观察信息失败: {e}", exc_info=True) # 保留默认值或错误信息 combined_summary = f"获取观察信息时出错: {e}" - # --- 获取麦麦状态 --- mai_state_description = f"麦麦当前状态: {current_mai_state.value}。" @@ -417,18 +415,23 @@ class SubHeartflowManager: if should_activate: # 检查CHAT限额 if current_chat_count < chat_limit: - logger.info(f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换...") + logger.info( + f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..." + ) await sub_hf.change_chat_state(ChatState.CHAT) if sub_hf.chat_state.chat_status == ChatState.CHAT: transitioned_to_chat += 1 - current_chat_count += 1 # 更新计数器 + current_chat_count += 1 # 更新计数器 else: logger.warning(f"{log_prefix} [{stream_name}] 尝试激活到CHAT失败。") else: - logger.info(f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。") + logger.info( + f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。" + ) except Exception as e: - logger.error(f"{log_prefix} [{stream_name}] LLM评估或状态转换(ABSENT->CHAT)时出错: {e}", exc_info=True) - + logger.error( + f"{log_prefix} [{stream_name}] LLM评估或状态转换(ABSENT->CHAT)时出错: {e}", exc_info=True + ) # --- 针对 CHAT 状态 --- elif current_subflow_state == ChatState.CHAT: @@ -451,11 +454,13 @@ class SubHeartflowManager: await sub_hf.change_chat_state(ChatState.ABSENT) if sub_hf.chat_state.chat_status == ChatState.ABSENT: transitioned_to_absent += 1 - current_chat_count -= 1 # 更新计数器 + current_chat_count -= 1 # 更新计数器 else: logger.warning(f"{log_prefix} [{stream_name}] 尝试转换为ABSENT失败。") except Exception as e: - logger.error(f"{log_prefix} [{stream_name}] LLM评估或状态转换(CHAT->ABSENT)时出错: {e}", exc_info=True) + logger.error( + f"{log_prefix} [{stream_name}] LLM评估或状态转换(CHAT->ABSENT)时出错: {e}", exc_info=True + ) # 可以选择性地为 FOCUSED 状态添加评估逻辑,例如判断是否降级回 CHAT 或 ABSENT @@ -465,7 +470,6 @@ class SubHeartflowManager: f" 成功转换到ABSENT: {transitioned_to_absent}." ) - async def _llm_evaluate_state_transition(self, prompt: str) -> bool: """ 使用 LLM 评估是否应进行状态转换。 @@ -479,8 +483,8 @@ class SubHeartflowManager: log_prefix = "[LLM状态评估]" try: # --- 真实的 LLM 调用 --- - response_text, _, model_name = await self.llm_state_evaluator.generate_response_async(prompt) - logger.debug(f"{log_prefix} 使用模型 {model_name} 评估,原始响应: {response_text}") + response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt) + logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: {response_text}") # 解析响应 - 这里需要根据你的LLM的确切输出来调整逻辑 # 假设 LLM 会明确回答 "是" 或 "否" if response_text and "是" in response_text.strip(): @@ -493,19 +497,11 @@ class SubHeartflowManager: logger.warning(f"{log_prefix} LLM 未明确回答 '是' 或 '否',响应: {response_text}") # 可以设定一个默认行为,例如默认不转换 return False - # --- 真实的 LLM 调用结束 --- - - # # --- 占位符逻辑:随机返回 True/False --- - # # 请在接入真实 LLM 后移除此部分 - # await asyncio.sleep(0.1) # 模拟LLM调用延迟 - # result = random.choice([True, False]) - # logger.debug(f"{log_prefix} (占位符) LLM评估结果: {'建议转换' if result else '建议不转换'}") - # return result - # # --- 占位符逻辑结束 --- except Exception as e: logger.error(f"{log_prefix} 调用 LLM 进行状态评估时出错: {e}", exc_info=True) - + traceback.print_exc() + return False def count_subflows_by_state(self, state: ChatState) -> int: """统计指定状态的子心流数量""" diff --git a/src/plugins/memory_system/Hippocampus.py b/src/plugins/memory_system/Hippocampus.py index 738e47c4..1e8ad885 100644 --- a/src/plugins/memory_system/Hippocampus.py +++ b/src/plugins/memory_system/Hippocampus.py @@ -404,7 +404,7 @@ class Hippocampus: # logger.info("没有找到有效的关键词节点") return [] - logger.info(f"有效的关键词: {', '.join(valid_keywords)}") + logger.debug(f"有效的关键词: {', '.join(valid_keywords)}") # 从每个关键词获取记忆 all_memories = [] @@ -576,7 +576,7 @@ class Hippocampus: # logger.info("没有找到有效的关键词节点") return [] - logger.info(f"有效的关键词: {', '.join(valid_keywords)}") + logger.debug(f"有效的关键词: {', '.join(valid_keywords)}") # 从每个关键词获取记忆 all_memories = [] @@ -761,7 +761,7 @@ class Hippocampus: # logger.info("没有找到有效的关键词节点") return 0 - logger.info(f"有效的关键词: {', '.join(valid_keywords)}") + logger.debug(f"有效的关键词: {', '.join(valid_keywords)}") # 从每个关键词获取记忆 activate_map = {} # 存储每个词的累计激活值 From 042e969292c50107ade9d4634d781ba0559db124 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sat, 26 Apr 2025 17:35:23 +0800 Subject: [PATCH 4/8] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E9=BA=A6?= =?UTF-8?q?=E9=BA=A6=E5=9B=9E=E5=A4=8D=E8=BF=87=E5=8E=BB=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/sub_heartflow.py | 18 +++ src/heart_flow/subheartflow_manager.py | 143 ++++++++++-------- src/plugins/heartFC_chat/heartFC_chat.py | 16 +- .../heartFC_chat/heartflow_prompt_builder.py | 1 + src/plugins/heartFC_chat/normal_chat.py | 67 +++++++- 5 files changed, 172 insertions(+), 73 deletions(-) diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index 33218f5f..efd0ea1e 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -86,8 +86,26 @@ class InterestChatting: logger.debug("后台兴趣更新任务已创建并启动。") def add_interest_dict(self, message: MessageRecv, interest_value: float, is_mentioned: bool): + """添加消息到兴趣字典 + + 参数: + message: 接收到的消息 + interest_value: 兴趣值 + is_mentioned: 是否被提及 + + 功能: + 1. 将消息添加到兴趣字典 + 2. 更新最后交互时间 + 3. 如果字典长度超过10,删除最旧的消息 + """ + # 添加新消息 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)) + self.interest_dict.pop(oldest_key) async def _calculate_decay(self): """计算兴趣值的衰减 diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index 9357ff3b..62d9e2f7 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -2,6 +2,7 @@ import asyncio import time import random from typing import Dict, Any, Optional, List +import json # 导入 json 模块 # 导入日志模块 from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG @@ -400,69 +401,65 @@ class SubHeartflowManager: if current_subflow_state == ChatState.ABSENT: # 构建Prompt prompt = ( - f"子心流 [{stream_name}] 当前处于非活跃(ABSENT)状态。\n" + f"子心流 [{stream_name}] 当前处于非活跃(ABSENT)状态.\n" f"{mai_state_description}\n" f"最近观察到的内容摘要:\n---\n{combined_summary}\n---\n" f"基于以上信息,该子心流是否表现出足够的活跃迹象或重要性," - f"值得将其唤醒并进入常规聊天(CHAT)状态?" - f"请回答 '是' 或 '否'。" + f"值得将其唤醒并进入常规聊天(CHAT)状态?\n" + f"请以 JSON 格式回答,包含一个键 'decision',其值为 true 或 false.\n" + f"例如:{{\"decision\": true}}\n" + f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 - try: - # 使用 self._llm_evaluate_state_transition - should_activate = await self._llm_evaluate_state_transition(prompt) - if should_activate: - # 检查CHAT限额 - if current_chat_count < chat_limit: - logger.info( - f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..." - ) - await sub_hf.change_chat_state(ChatState.CHAT) - if sub_hf.chat_state.chat_status == ChatState.CHAT: - transitioned_to_chat += 1 - current_chat_count += 1 # 更新计数器 - else: - logger.warning(f"{log_prefix} [{stream_name}] 尝试激活到CHAT失败。") + should_activate = await self._llm_evaluate_state_transition(prompt) + if should_activate is None: # 处理解析失败或意外情况 + logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") + continue + + if should_activate: + # 检查CHAT限额 + # 使用不上锁的版本,因为我们已经在锁内 + current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT) + if current_chat_count < chat_limit: + logger.info( + f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..." + ) + await sub_hf.change_chat_state(ChatState.CHAT) + if sub_hf.chat_state.chat_status == ChatState.CHAT: + transitioned_to_chat += 1 else: - logger.info( - f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。" - ) - except Exception as e: - logger.error( - f"{log_prefix} [{stream_name}] LLM评估或状态转换(ABSENT->CHAT)时出错: {e}", exc_info=True - ) + logger.warning(f"{log_prefix} [{stream_name}] 尝试激活到CHAT失败。") + else: + logger.info( + f"{log_prefix} [{stream_name}] LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。" + ) # --- 针对 CHAT 状态 --- elif current_subflow_state == ChatState.CHAT: # 构建Prompt prompt = ( - f"子心流 [{stream_name}] 当前处于常规聊天(CHAT)状态。\n" + f"子心流 [{stream_name}] 当前处于常规聊天(CHAT)状态.\n" f"{mai_state_description}\n" f"最近观察到的内容摘要:\n---\n{combined_summary}\n---\n" f"基于以上信息,该子心流是否表现出不活跃、对话结束或不再需要关注的迹象," - f"应该让其进入休眠(ABSENT)状态?" - f"请回答 '是' 或 '否'。" + f"应该让其进入休眠(ABSENT)状态?\n" + f"请以 JSON 格式回答,包含一个键 'decision',其值为 true (表示应休眠) 或 false (表示不应休眠).\n" + f"例如:{{\"decision\": true}}\n" + f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 - try: - # 使用 self._llm_evaluate_state_transition - should_deactivate = await self._llm_evaluate_state_transition(prompt) - if should_deactivate: - logger.info(f"{log_prefix} [{stream_name}] LLM建议进入ABSENT状态。正在尝试转换...") - await sub_hf.change_chat_state(ChatState.ABSENT) - if sub_hf.chat_state.chat_status == ChatState.ABSENT: - transitioned_to_absent += 1 - current_chat_count -= 1 # 更新计数器 - else: - logger.warning(f"{log_prefix} [{stream_name}] 尝试转换为ABSENT失败。") - except Exception as e: - logger.error( - f"{log_prefix} [{stream_name}] LLM评估或状态转换(CHAT->ABSENT)时出错: {e}", exc_info=True - ) + should_deactivate = await self._llm_evaluate_state_transition(prompt) + if should_deactivate is None: # 处理解析失败或意外情况 + logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") + continue - # 可以选择性地为 FOCUSED 状态添加评估逻辑,例如判断是否降级回 CHAT 或 ABSENT + if should_deactivate: + logger.info(f"{log_prefix} [{stream_name}] LLM建议进入ABSENT状态。正在尝试转换...") + await sub_hf.change_chat_state(ChatState.ABSENT) + if sub_hf.chat_state.chat_status == ChatState.ABSENT: + transitioned_to_absent += 1 logger.info( f"{log_prefix} LLM评估周期结束。" @@ -470,38 +467,58 @@ class SubHeartflowManager: f" 成功转换到ABSENT: {transitioned_to_absent}." ) - async def _llm_evaluate_state_transition(self, prompt: str) -> bool: + async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]: """ - 使用 LLM 评估是否应进行状态转换。 + 使用 LLM 评估是否应进行状态转换,期望 LLM 返回 JSON 格式。 Args: - prompt: 提供给 LLM 的提示信息。 + prompt: 提供给 LLM 的提示信息,要求返回 {"decision": true/false}。 Returns: - bool: True 表示应该转换,False 表示不应该转换。 + Optional[bool]: 如果成功解析 LLM 的 JSON 响应并提取了 'decision' 键的值,则返回该布尔值。 + 如果 LLM 调用失败、返回无效 JSON 或 JSON 中缺少 'decision' 键或其值不是布尔型,则返回 None。 """ log_prefix = "[LLM状态评估]" 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}") - # 解析响应 - 这里需要根据你的LLM的确切输出来调整逻辑 - # 假设 LLM 会明确回答 "是" 或 "否" - if response_text and "是" in response_text.strip(): - logger.debug(f"{log_prefix} LLM评估结果: 建议转换 (响应包含 '是')") - return True - elif response_text and "否" in response_text.strip(): - logger.debug(f"{log_prefix} LLM评估结果: 建议不转换 (响应包含 '否')") - return False - else: - logger.warning(f"{log_prefix} LLM 未明确回答 '是' 或 '否',响应: {response_text}") - # 可以设定一个默认行为,例如默认不转换 - return False + 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 = cleaned_response[4:].strip() + + data = json.loads(cleaned_response) + 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 # 值类型不正确 + + except json.JSONDecodeError as json_err: + logger.warning(f"{log_prefix} LLM 返回的响应不是有效的 JSON: {json_err}。响应: {response_text}") + # 尝试在非JSON响应中查找关键词作为后备方案 (可选) + if "true" in response_text.lower(): + logger.debug(f"{log_prefix} 在非JSON响应中找到 'true',解释为建议转换") + return True + if "false" in response_text.lower(): + logger.debug(f"{log_prefix} 在非JSON响应中找到 'false',解释为建议不转换") + return False + 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) + logger.error(f"{log_prefix} 调用 LLM 或处理其响应时出错: {e}", exc_info=True) traceback.print_exc() - return False + return None # LLM 调用或处理失败 def count_subflows_by_state(self, state: ChatState) -> int: """统计指定状态的子心流数量""" diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index e9577e41..2a33d067 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -404,10 +404,10 @@ class HeartFChatting: return False, "" # execute:执行 - with Timer("执行动作", cycle_timers): - return await self._handle_action( - action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time - ) + + return await self._handle_action( + action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time + ) except PlannerError as e: logger.error(f"{self.log_prefix} 规划错误: {e}") @@ -560,7 +560,7 @@ class HeartFChatting: observation = self.observations[0] if self.observations else None try: - with Timer("Wait New Msg", cycle_timers): + with Timer("等待新消息", cycle_timers): return await self._wait_for_new_message(observation, planner_start_db_time, self.log_prefix) except asyncio.CancelledError: logger.info(f"{self.log_prefix} 等待被中断") @@ -584,8 +584,8 @@ class HeartFChatting: logger.info(f"{log_prefix} 检测到新消息") return True - if time.monotonic() - wait_start_time > 300: - logger.warning(f"{log_prefix} 等待超时(300秒)") + if time.monotonic() - wait_start_time > 120: + logger.warning(f"{log_prefix} 等待超时(120秒)") return False await asyncio.sleep(1.5) @@ -604,8 +604,6 @@ class HeartFChatting: async def _handle_cycle_delay(self, action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str): """处理循环延迟""" cycle_duration = time.monotonic() - cycle_start_time - # if cycle_duration > 0.1: - # logger.debug(f"{log_prefix} HeartFChatting: 周期耗时 {cycle_duration:.2f}s.") try: sleep_duration = 0.0 diff --git a/src/plugins/heartFC_chat/heartflow_prompt_builder.py b/src/plugins/heartFC_chat/heartflow_prompt_builder.py index 584205a7..5308ce6e 100644 --- a/src/plugins/heartFC_chat/heartflow_prompt_builder.py +++ b/src/plugins/heartFC_chat/heartflow_prompt_builder.py @@ -67,6 +67,7 @@ def init_prompt(): 2. 文字回复(text_reply)适用: - 有实质性内容需要表达 +- 有人提到你,但你还没有回应他 - 可以追加emoji_query表达情绪(格式:情绪描述,如"俏皮的调侃") - 不要追加太多表情 diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index 6687421e..d7be9bef 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -1,6 +1,7 @@ import time import asyncio import traceback +import statistics # 导入 statistics 模块 from random import random from typing import List, Optional # 导入 Optional @@ -46,6 +47,8 @@ class NormalChat: self.gpt = NormalChatGenerator() 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 实例初始化完成。") @@ -317,6 +320,59 @@ class NormalChat: # 意愿管理器:注销当前message信息 (无论是否回复,只要处理过就删除) willing_manager.delete(message.message_info.message_id) + # --- 新增:处理初始高兴趣消息的私有方法 --- + async def _process_initial_interest_messages(self): + """处理启动时存在于 interest_dict 中的高兴趣消息。""" + items_to_process = list(self.interest_dict.items()) + if not items_to_process: + return # 没有初始消息,直接返回 + + logger.info(f"[{self.stream_name}] 发现 {len(items_to_process)} 条初始兴趣消息,开始处理高兴趣部分...") + interest_values = [item[1][1] for item in items_to_process] # 提取兴趣值列表 + + messages_to_reply = [] # 需要立即回复的消息 + + if len(interest_values) == 1: + # 如果只有一个消息,直接处理 + messages_to_reply.append(items_to_process[0]) + logger.info(f"[{self.stream_name}] 只有一条初始消息,直接处理。") + elif len(interest_values) > 1: + # 计算均值和标准差 + try: + 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}") + + # 找出高于阈值的消息 + for item in items_to_process: + msg_id, (message, interest_value, is_mentioned) = item + if interest_value > threshold: + 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},跳过初始处理。") + + # 处理需要回复的消息 + processed_count = 0 + for item in messages_to_reply: + 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 + ) + 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)} 条待轮询。") + # --- 新增结束 --- + # 保持 staticmethod, 因为不依赖实例状态, 但需要 chat 对象来获取日志上下文 @staticmethod def _check_ban_words(text: str, chat: ChatStream, userinfo: UserInfo) -> bool: @@ -350,11 +406,20 @@ class NormalChat: # 改为实例方法, 移除 chat 参数 async def start_chat(self): - """为此 NormalChat 实例关联的 ChatStream 启动聊天任务(如果尚未运行)。""" + """为此 NormalChat 实例关联的 ChatStream 启动聊天任务(如果尚未运行), + 并在启动前处理一次初始的高兴趣消息。""" if self._chat_task is None or self._chat_task.done(): + # --- 修改:调用新的私有方法处理初始消息 --- + await self._process_initial_interest_messages() + # --- 修改结束 --- + + # 启动后台轮询任务 + logger.info(f"[{self.stream_name}] 启动后台兴趣消息轮询任务...") task = asyncio.create_task(self._reply_interested_message()) task.add_done_callback(lambda t: self._handle_task_completion(t)) # 回调现在是实例方法 self._chat_task = task + else: + logger.info(f"[{self.stream_name}] 聊天任务已在运行中。") def _handle_task_completion(self, task: asyncio.Task): """任务完成回调处理""" From 6e4ba27ffb500ffea5478aa1566f3478df7c9927 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 09:35:36 +0000 Subject: [PATCH 5/8] =?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/heart_flow/sub_heartflow.py | 6 ++--- src/heart_flow/subheartflow_manager.py | 32 ++++++++++++++----------- src/plugins/heartFC_chat/normal_chat.py | 24 ++++++++++--------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index efd0ea1e..364303cc 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 62d9e2f7..46e34d1d 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 d7be9bef..912da352 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 对象来获取日志上下文 From e7f120319cce81c9affe7ea2f8f33a9ca72c18a3 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 18:13:11 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=B0=86PFC=E7=9A=84=E9=BA=A6=E9=BA=A6?= =?UTF-8?q?=E5=8F=91=E8=A8=80=E5=AD=98=E8=87=B3=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=EF=BC=8C=E5=88=A0=E6=8E=89=E6=89=8B=E5=8A=A8=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/conversation.py | 30 ------------------------------ src/plugins/PFC/pfc.py | 1 + 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 83081e80..37a35b7a 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -443,36 +443,6 @@ class Conversation: await self.direct_sender.send_message(chat_stream=self.chat_stream, content=reply_content) logger.info(f"消息已发送: {reply_content}") # 可以在发送后加个日志确认 - # --- 添加的立即更新状态逻辑开始 --- - try: - # 内层 try: 专门捕获手动更新状态时可能出现的错误 - # 创建一个代表刚刚发送的消息的字典 - bot_message_info = { - "message_id": f"bot_sent_{current_time}", # 创建一个简单的唯一ID - "time": current_time, - "user_info": UserInfo( # 使用 UserInfo 类构建用户信息 - user_id=str(global_config.BOT_QQ), - user_nickname=global_config.BOT_NICKNAME, - platform=self.chat_stream.platform, # 从 chat_stream 获取平台信息 - ).to_dict(), # 转换为字典格式存储 - "processed_plain_text": reply_content, # 使用发送的内容 - "detailed_plain_text": f"{int(current_time)},{global_config.BOT_NICKNAME}:{reply_content}", # 构造一个简单的详细文本, 时间戳取整 - # 可以根据需要添加其他字段,保持与 observation_info.chat_history 中其他消息结构一致 - } - - # 直接更新 ObservationInfo 实例 - if self.observation_info: - self.observation_info.chat_history.append(bot_message_info) # 将消息添加到历史记录末尾 - self.observation_info.last_bot_speak_time = current_time # 更新 Bot 最后发言时间 - self.observation_info.last_message_time = current_time # 更新最后消息时间 - logger.debug("已手动将Bot发送的消息添加到 ObservationInfo") - else: - logger.warning("无法手动更新 ObservationInfo:实例不存在") - - except Exception as update_err: - logger.error(f"手动更新 ObservationInfo 时出错: {update_err}") - # --- 添加的立即更新状态逻辑结束 --- - # 原有的触发更新和等待代码 self.chat_observer.trigger_update() if not await self.chat_observer.wait_for_update(): diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index 033cf822..ac833862 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -376,6 +376,7 @@ class DirectMessageSender: # 发送消息 try: await self.send_via_ws(message) + await self.storage.store_message(message, chat_stream) logger.success(f"PFC消息已发送: {content}") except Exception as e: logger.error(f"PFC消息发送失败: {str(e)}") From 293a03960a2e024a6579b05be5e87fcbb83645a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Sat, 26 Apr 2025 18:40:37 +0800 Subject: [PATCH 7/8] fix: Ruff --- src/plugins/PFC/conversation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 37a35b7a..9e675ac3 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,7 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat -from ...config.config import global_config +# from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message from .pfc_types import ConversationState @@ -436,7 +436,7 @@ class Conversation: try: # 外层 try: 捕获发送消息和后续处理中的主要错误 - current_time = time.time() # 获取当前时间戳 + _current_time = time.time() # 获取当前时间戳 reply_content = self.generated_reply # 获取要发送的内容 # 发送消息 From 10282f3d0c217d5be06d45e0b66c00f0383e5bd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 10:40:50 +0000 Subject: [PATCH 8/8] =?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/plugins/PFC/conversation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 9e675ac3..c56cc3e1 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,6 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat + # from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message