From 75e89c78d5a8334b20193a2bbc5a6ff5ae021e63 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 22 Apr 2025 16:42:45 +0000 Subject: [PATCH] =?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/do_tool/tool_use.py | 4 +- src/heart_flow/heartflow.py | 143 +++++++++++------- src/heart_flow/observation.py | 1 - src/heart_flow/sub_heartflow.py | 58 ++++--- src/plugins/chat/message_sender.py | 87 ++++++----- src/plugins/heartFC_chat/heartFC_chat.py | 50 +++--- src/plugins/heartFC_chat/heartFC_generator.py | 4 +- .../heartFC_chat/heartflow_prompt_builder.py | 49 +++--- src/plugins/heartFC_chat/normal_chat.py | 13 +- .../heartFC_chat/normal_chat_generator.py | 14 +- src/plugins/utils/chat_message_builder.py | 5 +- 11 files changed, 235 insertions(+), 193 deletions(-) diff --git a/src/do_tool/tool_use.py b/src/do_tool/tool_use.py index 997ba7ee5..4134f83bb 100644 --- a/src/do_tool/tool_use.py +++ b/src/do_tool/tool_use.py @@ -24,7 +24,9 @@ class ToolUser: ) @staticmethod - async def _build_tool_prompt(message_txt: str, chat_stream: ChatStream = None, observation: ChattingObservation = None): + async def _build_tool_prompt( + message_txt: str, chat_stream: ChatStream = None, observation: ChattingObservation = None + ): """构建工具使用的提示词 Args: diff --git a/src/heart_flow/heartflow.py b/src/heart_flow/heartflow.py index 0680984ee..e74364ea1 100644 --- a/src/heart_flow/heartflow.py +++ b/src/heart_flow/heartflow.py @@ -15,11 +15,12 @@ import enum import os # 新增 import json # 新增 from src.plugins.chat.chat_stream import chat_manager # 新增 + # --- Add imports for merged dependencies --- from src.plugins.heartFC_chat.heartFC_generator import ResponseGenerator from src.do_tool.tool_use import ToolUser -from src.plugins.chat.emoji_manager import emoji_manager # Module instance -from src.plugins.person_info.relationship_manager import relationship_manager # Module instance +from src.plugins.chat.emoji_manager import emoji_manager # Module instance +from src.plugins.person_info.relationship_manager import relationship_manager # Module instance # --- End imports --- heartflow_config = LogConfig( @@ -31,9 +32,10 @@ logger = get_module_logger("heartflow", config=heartflow_config) # Type hinting for circular dependency if TYPE_CHECKING: - from src.heart_flow.sub_heartflow import SubHeartflow, ChatState # Keep SubHeartflow here too + from src.heart_flow.sub_heartflow import SubHeartflow, ChatState # Keep SubHeartflow here too # from src.plugins.heartFC_chat.heartFC_controler import HeartFCController # No longer needed + def init_prompt(): prompt = "" prompt += "你刚刚在做的事情是:{schedule_info}\n" @@ -64,7 +66,7 @@ LOG_INTERVAL_SECONDS = 3 # 日志记录间隔 (例如:3秒) - 保持与 inter # --- 结束新增常量 --- # --- 新增:状态更新常量 --- -STATE_UPDATE_INTERVAL_SECONDS = 30 # 状态更新检查间隔(秒) +STATE_UPDATE_INTERVAL_SECONDS = 30 # 状态更新检查间隔(秒) FIVE_MINUTES = 1 * 60 FIFTEEN_MINUTES = 5 * 60 TWENTY_MINUTES = 10 * 60 @@ -109,12 +111,11 @@ class MaiState(enum.Enum): class MaiStateInfo: def __init__(self): - # 使用枚举类型初始化状态,默认为正常聊天 self.mai_status: MaiState = MaiState.OFFLINE - self.mai_status_history = [] # 历史状态,包含 状态,最后时间 - self.last_status_change_time: float = time.time() # 新增:状态最后改变时间 - self.last_5min_check_time: float = time.time() # 新增:上次5分钟规则检查时间 + self.mai_status_history = [] # 历史状态,包含 状态,最后时间 + self.last_status_change_time: float = time.time() # 新增:状态最后改变时间 + self.last_5min_check_time: float = time.time() # 新增:上次5分钟规则检查时间 self.normal_chatting = [] self.focused_chatting = [] @@ -125,11 +126,11 @@ class MaiStateInfo: # 新增更新聊天状态的方法 def update_mai_status(self, new_status: MaiState): """更新聊天状态""" - if isinstance(new_status, MaiState) and new_status != self.mai_status: # 只有状态实际改变时才更新 + if isinstance(new_status, MaiState) and new_status != self.mai_status: # 只有状态实际改变时才更新 self.mai_status = new_status current_time = time.time() - self.last_status_change_time = current_time # 更新状态改变时间 - self.last_5min_check_time = current_time # 重置5分钟检查计时器 + self.last_status_change_time = current_time # 更新状态改变时间 + self.last_5min_check_time = current_time # 重置5分钟检查计时器 # 将新状态和时间戳添加到历史记录 self.mai_status_history.append((new_status, current_time)) logger.info(f"麦麦状态更新为: {self.mai_status.value}") @@ -148,14 +149,16 @@ class Heartflow: model=global_config.llm_heartflow, temperature=0.6, max_tokens=1000, request_type="heart_flow" ) - self._subheartflows: Dict[Any, 'SubHeartflow'] = {} # Update type hint + self._subheartflows: Dict[Any, "SubHeartflow"] = {} # Update type hint # --- Dependencies moved from HeartFCController --- self.gpt_instance = ResponseGenerator() - self.mood_manager = MoodManager.get_instance() # Note: MaiStateInfo also has one, consider consolidating later if needed + self.mood_manager = ( + MoodManager.get_instance() + ) # Note: MaiStateInfo also has one, consider consolidating later if needed self.tool_user_instance = ToolUser() - self.emoji_manager_instance = emoji_manager # Module instance - self.relationship_manager_instance = relationship_manager # Module instance + self.emoji_manager_instance = emoji_manager # Module instance + self.relationship_manager_instance = relationship_manager # Module instance # --- End moved dependencies --- # --- Background Task Management --- @@ -163,7 +166,7 @@ class Heartflow: self._ensure_log_directory() # 初始化时确保目录存在 self._cleanup_task: Optional[asyncio.Task] = None self._logging_task: Optional[asyncio.Task] = None - self._state_update_task: Optional[asyncio.Task] = None # 新增:状态更新任务 + self._state_update_task: Optional[asyncio.Task] = None # 新增:状态更新任务 # 注意:衰减任务 (_decay_task) 不再需要,衰减在 SubHeartflow 的 InterestChatting 内部处理 # --- End moved dependencies --- @@ -243,24 +246,24 @@ class Heartflow: current_time = time.time() # 获取更新前的状态 previous_status = self.current_state.mai_status - current_status = self.current_state.mai_status # 保持此行以进行后续逻辑 + current_status = self.current_state.mai_status # 保持此行以进行后续逻辑 time_in_current_status = current_time - self.current_state.last_status_change_time time_since_last_5min_check = current_time - self.current_state.last_5min_check_time - next_state = None # 预设下一状态为 None + next_state = None # 预设下一状态为 None # --- 状态转换逻辑 (保持不变) --- # 1. 通用规则:每5分钟检查 (对于非 OFFLINE 状态) if time_since_last_5min_check >= FIVE_MINUTES: - self.current_state.last_5min_check_time = current_time # 重置5分钟检查计时器(无论是否切换) + self.current_state.last_5min_check_time = current_time # 重置5分钟检查计时器(无论是否切换) if current_status != MaiState.OFFLINE: - if random.random() < 0.10: # 10% 概率切换到 OFFLINE + if random.random() < 0.10: # 10% 概率切换到 OFFLINE logger.debug(f"[Heartflow State] 触发5分钟规则,从 {current_status.value} 切换到 OFFLINE") - next_state = MaiState.OFFLINE # 设置 next_state 而不是直接更新 + next_state = MaiState.OFFLINE # 设置 next_state 而不是直接更新 # self.current_state.update_mai_status(MaiState.OFFLINE) # continue # 状态已改变,进入下一轮循环 # 2. 状态持续时间规则 (仅在未被5分钟规则覆盖时执行) - if next_state is None: # 仅当5分钟规则未触发切换时检查持续时间 + if next_state is None: # 仅当5分钟规则未触发切换时检查持续时间 if current_status == MaiState.OFFLINE: # OFFLINE 状态下,检查是否已持续5分钟 if time_in_current_status >= FIVE_MINUTES: @@ -274,26 +277,26 @@ class Heartflow: # 保持 OFFLINE,重置计时器以开始新的5分钟计时 logger.debug("[Heartflow State] OFFLINE 持续时间达到,保持 OFFLINE,重置计时器") self.current_state.last_status_change_time = current_time - self.current_state.last_5min_check_time = current_time # 保持一致 + self.current_state.last_5min_check_time = current_time # 保持一致 # 显式将 next_state 设为 OFFLINE 以便后续处理 next_state = MaiState.OFFLINE elif current_status == MaiState.PEEKING: - if time_in_current_status >= FIVE_MINUTES: # PEEKING 最多持续 5 分钟 + if time_in_current_status >= FIVE_MINUTES: # PEEKING 最多持续 5 分钟 weights = [50, 30, 20] choices_list = [MaiState.OFFLINE, MaiState.NORMAL_CHAT, MaiState.FOCUSED_CHAT] next_state = random.choices(choices_list, weights=weights, k=1)[0] logger.debug(f"[Heartflow State] PEEKING 持续时间达到,切换到 {next_state.value}") elif current_status == MaiState.NORMAL_CHAT: - if time_in_current_status >= FIFTEEN_MINUTES: # NORMAL_CHAT 最多持续 15 分钟 + if time_in_current_status >= FIFTEEN_MINUTES: # NORMAL_CHAT 最多持续 15 分钟 weights = [50, 50] choices_list = [MaiState.OFFLINE, MaiState.FOCUSED_CHAT] next_state = random.choices(choices_list, weights=weights, k=1)[0] logger.debug(f"[Heartflow State] NORMAL_CHAT 持续时间达到,切换到 {next_state.value}") elif current_status == MaiState.FOCUSED_CHAT: - if time_in_current_status >= TWENTY_MINUTES: # FOCUSED_CHAT 最多持续 20 分钟 + if time_in_current_status >= TWENTY_MINUTES: # FOCUSED_CHAT 最多持续 20 分钟 weights = [80, 20] choices_list = [MaiState.OFFLINE, MaiState.NORMAL_CHAT] next_state = random.choices(choices_list, weights=weights, k=1)[0] @@ -325,7 +328,7 @@ class Heartflow: if time_in_current_status >= FIVE_MINUTES: # 确保计时器已在上面重置,这里无需操作,只记录日志 logger.debug("[Heartflow State] 保持 OFFLINE 状态,计时器已重置。") - pass # 无需状态转换,也无需调用激活/停用逻辑 + pass # 无需状态转换,也无需调用激活/停用逻辑 # --- 如果没有确定 next_state (即没有触发任何切换规则) --- # # logger.debug(f"[Heartflow State] 状态未改变,保持 {current_status.value}") # 减少日志噪音 @@ -340,10 +343,15 @@ class Heartflow: for sub_hf in subflows_snapshot: # Double-check if subflow still exists and is in CHAT state - if sub_hf.subheartflow_id in self._subheartflows and sub_hf.chat_state.chat_status == ChatState.CHAT: + if ( + sub_hf.subheartflow_id in self._subheartflows + and sub_hf.chat_state.chat_status == ChatState.CHAT + ): evaluated_count += 1 if sub_hf.should_evaluate_reply(): - stream_name = chat_manager.get_stream_name(sub_hf.subheartflow_id) or sub_hf.subheartflow_id + stream_name = ( + chat_manager.get_stream_name(sub_hf.subheartflow_id) or sub_hf.subheartflow_id + ) log_prefix = f"[{stream_name}]" logger.info(f"{log_prefix} 兴趣概率触发,尝试将状态从 CHAT 提升到 FOCUSED") # set_chat_state handles limit checks and HeartFChatting creation internally @@ -352,10 +360,12 @@ class Heartflow: if sub_hf.chat_state.chat_status == ChatState.FOCUSED: promoted_count += 1 # else: # No need to log every non-trigger event - # logger.trace(f"[{sub_hf.subheartflow_id}] In CHAT state, but should_evaluate_reply returned False.") + # logger.trace(f"[{sub_hf.subheartflow_id}] In CHAT state, but should_evaluate_reply returned False.") if evaluated_count > 0: - logger.debug(f"[Heartflow Interest Eval] Evaluated {evaluated_count} CHAT flows. Promoted {promoted_count} to FOCUSED.") + logger.debug( + f"[Heartflow Interest Eval] Evaluated {evaluated_count} CHAT flows. Promoted {promoted_count} to FOCUSED." + ) except Exception as e: logger.error(f"[Heartflow] 兴趣评估任务出错: {e}") @@ -431,7 +441,6 @@ class Heartflow: # logger.info(f"[Heartflow] 清理完成。没有流符合移除条件。当前数量: {initial_count}") # 减少日志噪音 pass - async def heartflow_start_working(self): # 启动清理任务 (使用新的 periodic_cleanup_task) if self._cleanup_task is None or self._cleanup_task.done(): @@ -593,7 +602,7 @@ class Heartflow: return "(想法汇总时发生错误...)" # --- Add helper method to count subflows by state --- # - def count_subflows_by_state(self, target_state: 'ChatState') -> int: + def count_subflows_by_state(self, target_state: "ChatState") -> int: """Counts the number of subheartflows currently in the specified state.""" count = 0 # Use items() directly for read-only iteration if thread safety isn't a major concern here @@ -604,9 +613,10 @@ class Heartflow: if flow.subheartflow_id in self._subheartflows and flow.chat_state.chat_status == target_state: count += 1 return count + # --- End helper method --- # - async def create_subheartflow(self, subheartflow_id: Any) -> Optional['SubHeartflow']: + async def create_subheartflow(self, subheartflow_id: Any) -> Optional["SubHeartflow"]: """ 获取或创建一个新的SubHeartflow实例。 创建本身不受限,因为初始状态是ABSENT。 @@ -627,7 +637,6 @@ class Heartflow: await observation.initialize() subheartflow.add_observation(observation) - # 创建并存储后台任务 (SubHeartflow 自己的后台任务) subheartflow.task = asyncio.create_task(subheartflow.subheartflow_start_working()) logger.debug(f"[Heartflow] 为 {subheartflow_id} 创建后台任务成功,添加 observation 成功") @@ -641,7 +650,7 @@ class Heartflow: logger.error(traceback.format_exc()) return None - def get_subheartflow(self, observe_chat_id: Any) -> Optional['SubHeartflow']: + def get_subheartflow(self, observe_chat_id: Any) -> Optional["SubHeartflow"]: """获取指定ID的SubHeartflow实例""" return self._subheartflows.get(observe_chat_id) @@ -659,13 +668,13 @@ class Heartflow: # --- 新增:在取消任务和删除前,先设置状态为 ABSENT 以关闭 HeartFChatting --- try: if subheartflow.chat_state.chat_status != ChatState.ABSENT: - logger.debug(f"[Heartflow Limits] 将子心流 {stream_name} 状态设置为 ABSENT 以确保资源释放...") - await subheartflow.set_chat_state(ChatState.ABSENT) # 调用异步方法 + logger.debug(f"[Heartflow Limits] 将子心流 {stream_name} 状态设置为 ABSENT 以确保资源释放...") + await subheartflow.set_chat_state(ChatState.ABSENT) # 调用异步方法 else: - logger.debug(f"[Heartflow Limits] 子心流 {stream_name} 已经是 ABSENT 状态。") + logger.debug(f"[Heartflow Limits] 子心流 {stream_name} 已经是 ABSENT 状态。") except Exception as e: - logger.error(f"[Heartflow Limits] 在停止子心流 {stream_name} 时设置状态为 ABSENT 出错: {e}") - # 即使出错,仍继续尝试停止任务和移除 + logger.error(f"[Heartflow Limits] 在停止子心流 {stream_name} 时设置状态为 ABSENT 出错: {e}") + # 即使出错,仍继续尝试停止任务和移除 # --- 结束新增逻辑 --- # 标记停止并取消任务 @@ -692,12 +701,14 @@ class Heartflow: """根据当前的 MaiState 强制执行 SubHeartflow 数量限制""" normal_limit = current_mai_state.get_normal_chat_max_num() focused_limit = current_mai_state.get_focused_chat_max_num() - logger.debug(f"[Heartflow Limits] 执行限制检查。当前状态: {current_mai_state.value}, Normal上限: {normal_limit}, Focused上限: {focused_limit}") + logger.debug( + f"[Heartflow Limits] 执行限制检查。当前状态: {current_mai_state.value}, Normal上限: {normal_limit}, Focused上限: {focused_limit}" + ) # 分类并统计当前 subheartflows normal_flows = [] focused_flows = [] - other_flows = [] # e.g., ABSENT + other_flows = [] # e.g., ABSENT # 创建快照以安全迭代 items_snapshot = list(self._subheartflows.items()) @@ -713,7 +724,9 @@ class Heartflow: else: other_flows.append((flow_id, flow.last_active_time)) - logger.debug(f"[Heartflow Limits] 当前计数 - Normal: {len(normal_flows)}, Focused: {len(focused_flows)}, Other: {len(other_flows)}") + logger.debug( + f"[Heartflow Limits] 当前计数 - Normal: {len(normal_flows)}, Focused: {len(focused_flows)}, Other: {len(other_flows)}" + ) stopped_count = 0 @@ -726,32 +739,40 @@ class Heartflow: # 停止最不活跃的超额部分 for i in range(excess_count): flow_id_to_stop = normal_flows[i][0] - if await self._stop_subheartflow(flow_id_to_stop, f"Normal (CHAT) 状态超出上限 ({normal_limit}),停止最不活跃的实例"): + if await self._stop_subheartflow( + flow_id_to_stop, f"Normal (CHAT) 状态超出上限 ({normal_limit}),停止最不活跃的实例" + ): stopped_count += 1 # 重新获取 focused_flows 列表,因为上面的停止操作可能已经改变了状态或移除了实例 focused_flows = [] items_snapshot_after_normal = list(self._subheartflows.items()) for flow_id, flow in items_snapshot_after_normal: - if flow_id not in self._subheartflows: - continue # Double check + if flow_id not in self._subheartflows: + continue # Double check if flow.chat_state.chat_status == ChatState.FOCUSED: focused_flows.append((flow_id, flow.last_active_time)) # 检查 Focused (FOCUSED) 限制 if len(focused_flows) > focused_limit: excess_count = len(focused_flows) - focused_limit - logger.info(f"[Heartflow Limits] 检测到 Focused (FOCUSED) 状态超额 {excess_count} 个。上限: {focused_limit}") + logger.info( + f"[Heartflow Limits] 检测到 Focused (FOCUSED) 状态超额 {excess_count} 个。上限: {focused_limit}" + ) # 按 last_active_time 升序排序 focused_flows.sort(key=lambda item: item[1]) # 停止最不活跃的超额部分 for i in range(excess_count): flow_id_to_stop = focused_flows[i][0] - if await self._stop_subheartflow(flow_id_to_stop, f"Focused (FOCUSED) 状态超出上限 ({focused_limit}),停止最不活跃的实例"): + if await self._stop_subheartflow( + flow_id_to_stop, f"Focused (FOCUSED) 状态超出上限 ({focused_limit}),停止最不活跃的实例" + ): stopped_count += 1 if stopped_count > 0: - logger.info(f"[Heartflow Limits] 限制执行完成,共停止了 {stopped_count} 个子心流。当前总数: {len(self._subheartflows)}") + logger.info( + f"[Heartflow Limits] 限制执行完成,共停止了 {stopped_count} 个子心流。当前总数: {len(self._subheartflows)}" + ) else: logger.debug(f"[Heartflow Limits] 限制检查完成,无需停止子心流。当前总数: {len(self._subheartflows)}") @@ -765,7 +786,11 @@ class Heartflow: # 使用快照进行迭代 all_flows_snapshot = list(self._subheartflows.values()) - absent_flows = [flow for flow in all_flows_snapshot if flow.subheartflow_id in self._subheartflows and flow.chat_state.chat_status == ChatState.ABSENT] + absent_flows = [ + flow + for flow in all_flows_snapshot + if flow.subheartflow_id in self._subheartflows and flow.chat_state.chat_status == ChatState.ABSENT + ] num_to_activate = min(limit, len(absent_flows)) @@ -773,13 +798,18 @@ class Heartflow: logger.info(f"[Heartflow Activate] 没有处于 ABSENT 状态的子心流可供激活至 CHAT (上限: {limit})。") return - logger.info(f"[Heartflow Activate] 将随机选择 {num_to_activate} 个 (上限 {limit}) ABSENT 子心流激活至 CHAT 状态。") + logger.info( + f"[Heartflow Activate] 将随机选择 {num_to_activate} 个 (上限 {limit}) ABSENT 子心流激活至 CHAT 状态。" + ) selected_flows = random.sample(absent_flows, num_to_activate) activated_count = 0 for flow in selected_flows: # 再次检查 flow 是否仍然存在且状态为 ABSENT (以防并发修改) - if flow.subheartflow_id in self._subheartflows and self._subheartflows[flow.subheartflow_id].chat_state.chat_status == ChatState.ABSENT: + if ( + flow.subheartflow_id in self._subheartflows + and self._subheartflows[flow.subheartflow_id].chat_state.chat_status == ChatState.ABSENT + ): stream_name = chat_manager.get_stream_name(flow.subheartflow_id) or flow.subheartflow_id logger.debug(f"[Heartflow Activate] 正在将子心流 {stream_name} 状态设置为 CHAT。") # 调用 set_chat_state,它内部会处理日志记录 @@ -809,7 +839,7 @@ class Heartflow: for flow_id in flow_ids_snapshot: subflow = self._subheartflows.get(flow_id) if not subflow: - continue # Subflow 可能在迭代过程中被清理 + continue # Subflow 可能在迭代过程中被清理 stream_name = chat_manager.get_stream_name(flow_id) or flow_id @@ -835,11 +865,14 @@ class Heartflow: logger.error(f"[Heartflow Deactivate] 停用子心流 {stream_name} 时出错: {e}") logger.error(traceback.format_exc()) - logger.info(f"[Heartflow Deactivate] 完成停用,共将 {deactivated_count} 个子心流设置为 ABSENT 状态 (不包括已是 ABSENT 的)。") + logger.info( + f"[Heartflow Deactivate] 完成停用,共将 {deactivated_count} 个子心流设置为 ABSENT 状态 (不包括已是 ABSENT 的)。" + ) except Exception as e: logger.error(f"[Heartflow Deactivate] 停用所有子心流时出错: {e}") logger.error(traceback.format_exc()) + init_prompt() # 创建一个全局的管理器实例 heartflow = Heartflow() diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index 173463db3..ba4d23de9 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -137,7 +137,6 @@ class ChattingObservation(Observation): ) self.mid_memory_info = mid_memory_str - self.talking_message_str = await build_readable_messages(messages=self.talking_message, timestamp_mode="normal") logger.trace( diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index d9ad0c0b2..650b51961 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -20,9 +20,9 @@ from src.plugins.heartFC_chat.heartFC_chat import HeartFChatting # Type hinting for circular dependency if TYPE_CHECKING: - from .heartflow import Heartflow # Import Heartflow for type hinting - from .sub_heartflow import ChatState # Keep ChatState here too? - from src.plugins.heartFC_chat.heartFC_chat import HeartFChatting # <-- Add for type hint + from .heartflow import Heartflow # Import Heartflow for type hinting + from .sub_heartflow import ChatState # Keep ChatState here too? + from src.plugins.heartFC_chat.heartFC_chat import HeartFChatting # <-- Add for type hint # 定义常量 (从 interest.py 移动过来) MAX_INTEREST = 15.0 @@ -92,7 +92,7 @@ class InterestChatting: increase_rate=probability_increase_rate_per_second, decay_factor=global_config.probability_decay_factor_per_second, max_probability=max_reply_probability, - state_change_callback: Optional[Callable[[ChatState], None]] = None + state_change_callback: Optional[Callable[[ChatState], None]] = None, ): self.interest_level: float = 0.0 self.last_update_time: float = time.time() @@ -231,9 +231,9 @@ class InterestChatting: class SubHeartflow: - def __init__(self, subheartflow_id, parent_heartflow: 'Heartflow'): + def __init__(self, subheartflow_id, parent_heartflow: "Heartflow"): """子心流初始化函数 - + Args: subheartflow_id: 子心流唯一标识符 parent_heartflow: 父级心流实例 @@ -242,27 +242,27 @@ class SubHeartflow: self.subheartflow_id = subheartflow_id self.parent_heartflow = parent_heartflow self.bot_name = global_config.BOT_NICKNAME # 机器人昵称 - + # 思维状态相关 self.current_mind = "你什么也没想" # 当前想法 self.past_mind = [] # 历史想法记录 self.main_heartflow_info = "" # 主心流信息 - + # 聊天状态管理 self.chat_state: ChatStateInfo = ChatStateInfo() # 聊天状态信息 self.interest_chatting = InterestChatting(state_change_callback=self.set_chat_state) # 兴趣聊天系统 - + # 活动状态管理 self.last_active_time = time.time() # 最后活跃时间 self.is_active = False # 是否活跃标志 self.should_stop = False # 停止标志 self.task: Optional[asyncio.Task] = None # 后台任务 - self.heart_fc_instance: Optional['HeartFChatting'] = None # <-- Add instance variable - + self.heart_fc_instance: Optional["HeartFChatting"] = None # <-- Add instance variable + # 观察和知识系统 self.observations: List[ChattingObservation] = [] # 观察列表 self.running_knowledges = [] # 运行中的知识 - + # LLM模型配置 self.llm_model = LLMRequest( model=global_config.llm_sub_heartflow, @@ -271,13 +271,13 @@ class SubHeartflow: request_type="sub_heart_flow", ) - async def set_chat_state(self, new_state: 'ChatState'): + async def set_chat_state(self, new_state: "ChatState"): """更新sub_heartflow的聊天状态,并管理 HeartFChatting 实例""" current_state = self.chat_state.chat_status if current_state == new_state: logger.trace(f"[{self.subheartflow_id}] State already {current_state.value}, no change.") - return # No change needed + return # No change needed log_prefix = f"[{chat_manager.get_stream_name(self.subheartflow_id) or self.subheartflow_id}]" current_mai_state = self.parent_heartflow.current_state.mai_status @@ -288,10 +288,14 @@ class SubHeartflow: current_chat_count = self.parent_heartflow.count_subflows_by_state(ChatState.CHAT) if current_chat_count >= normal_limit: - logger.debug(f"{log_prefix} 拒绝从 {current_state.value} 转换到 CHAT。原因:CHAT 状态已达上限 ({normal_limit})。当前数量: {current_chat_count}") - return # Block the state transition + logger.debug( + f"{log_prefix} 拒绝从 {current_state.value} 转换到 CHAT。原因:CHAT 状态已达上限 ({normal_limit})。当前数量: {current_chat_count}" + ) + return # Block the state transition else: - logger.debug(f"{log_prefix} 允许从 {current_state.value} 转换到 CHAT (上限: {normal_limit}, 当前: {current_chat_count})" ) + logger.debug( + f"{log_prefix} 允许从 {current_state.value} 转换到 CHAT (上限: {normal_limit}, 当前: {current_chat_count})" + ) # If transitioning out of FOCUSED, shut down HeartFChatting first if current_state == ChatState.FOCUSED and self.heart_fc_instance: logger.info(f"{log_prefix} 从 FOCUSED 转换到 CHAT,正在关闭 HeartFChatting...") @@ -304,10 +308,14 @@ class SubHeartflow: current_focused_count = self.parent_heartflow.count_subflows_by_state(ChatState.FOCUSED) if current_focused_count >= focused_limit: - logger.debug(f"{log_prefix} 拒绝从 {current_state.value} 转换到 FOCUSED。原因:FOCUSED 状态已达上限 ({focused_limit})。当前数量: {current_focused_count}") - return # Block the state transition + logger.debug( + f"{log_prefix} 拒绝从 {current_state.value} 转换到 FOCUSED。原因:FOCUSED 状态已达上限 ({focused_limit})。当前数量: {current_focused_count}" + ) + return # Block the state transition else: - logger.debug(f"{log_prefix} 允许从 {current_state.value} 转换到 FOCUSED (上限: {focused_limit}, 当前: {current_focused_count})" ) + logger.debug( + f"{log_prefix} 允许从 {current_state.value} 转换到 FOCUSED (上限: {focused_limit}, 当前: {current_focused_count})" + ) if not self.heart_fc_instance: logger.info(f"{log_prefix} 状态转为 FOCUSED,创建并初始化 HeartFChatting 实例...") try: @@ -323,14 +331,16 @@ class SubHeartflow: await self.heart_fc_instance.add_time() logger.info(f"{log_prefix} HeartFChatting 实例已创建并启动。") else: - logger.error(f"{log_prefix} HeartFChatting 实例初始化失败,状态回滚到 {current_state.value}") + logger.error( + f"{log_prefix} HeartFChatting 实例初始化失败,状态回滚到 {current_state.value}" + ) self.heart_fc_instance = None - return # Prevent state change if HeartFChatting fails to init + return # Prevent state change if HeartFChatting fails to init except Exception as e: logger.error(f"{log_prefix} 创建 HeartFChatting 实例时出错: {e}") logger.error(traceback.format_exc()) self.heart_fc_instance = None - return # Prevent state change on error + return # Prevent state change on error else: logger.warning(f"{log_prefix} 尝试进入 FOCUSED 状态,但 HeartFChatting 实例已存在。") @@ -341,13 +351,11 @@ class SubHeartflow: await self.heart_fc_instance.shutdown() self.heart_fc_instance = None - # --- Update state and timestamp if transition is allowed --- # 更新状态必须放在所有检查和操作之后 self.chat_state.chat_status = new_state self.last_active_time = time.time() logger.info(f"{log_prefix} 聊天状态从 {current_state.value} 变更为 {new_state.value}") - async def subheartflow_start_working(self): while True: if self.should_stop: diff --git a/src/plugins/chat/message_sender.py b/src/plugins/chat/message_sender.py index 726b99cf3..a737d99cf 100644 --- a/src/plugins/chat/message_sender.py +++ b/src/plugins/chat/message_sender.py @@ -4,6 +4,7 @@ import time from typing import Dict, List, Optional, Union from src.common.logger import get_module_logger + # from ...common.database import db # 数据库依赖似乎不需要了,注释掉 from ..message.api import global_api from .message import MessageSending, MessageThinking, MessageSet @@ -75,7 +76,7 @@ class MessageSender: await self.send_via_ws(message) else: await self.send_via_ws(message) - logger.success(f"发送消息 '{message_preview}' 成功") # 调整日志格式 + logger.success(f"发送消息 '{message_preview}' 成功") # 调整日志格式 except Exception as e: logger.error(f"发送消息 '{message_preview}' 失败: {str(e)}") @@ -86,7 +87,7 @@ class MessageContainer: def __init__(self, chat_id: str, max_size: int = 100): self.chat_id = chat_id self.max_size = max_size - self.messages: List[Union[MessageThinking, MessageSending]] = [] # 明确类型 + self.messages: List[Union[MessageThinking, MessageSending]] = [] # 明确类型 self.last_send_time = 0 self.thinking_wait_timeout = 20 # 思考等待超时时间(秒) - 从旧 sender 合并 @@ -118,7 +119,7 @@ class MessageContainer: earliest_message = None for msg in self.messages: # 确保消息有 thinking_start_time 属性 - msg_time = getattr(msg, 'thinking_start_time', float('inf')) + msg_time = getattr(msg, "thinking_start_time", float("inf")) if msg_time < earliest_time: earliest_time = msg_time earliest_message = msg @@ -156,7 +157,7 @@ class MessageContainer: def get_all_messages(self) -> List[Union[MessageSending, MessageThinking]]: """获取所有消息""" - return list(self.messages) # 返回副本 + return list(self.messages) # 返回副本 class MessageManager: @@ -164,29 +165,28 @@ class MessageManager: def __init__(self): self.containers: Dict[str, MessageContainer] = {} - self.storage = MessageStorage() # 添加 storage 实例 - self._running = True # 处理器运行状态 - self._container_lock = asyncio.Lock() # 保护 containers 字典的锁 + self.storage = MessageStorage() # 添加 storage 实例 + self._running = True # 处理器运行状态 + self._container_lock = asyncio.Lock() # 保护 containers 字典的锁 # self.message_sender = MessageSender() # 创建发送器实例 (改为全局实例) async def start(self): """启动后台处理器任务。""" # 检查是否已有任务在运行,避免重复启动 - if hasattr(self, '_processor_task') and not self._processor_task.done(): - logger.warning("Processor task already running.") - return + if hasattr(self, "_processor_task") and not self._processor_task.done(): + logger.warning("Processor task already running.") + return self._processor_task = asyncio.create_task(self._start_processor_loop()) logger.info("MessageManager processor task started.") def stop(self): - """停止后台处理器任务。""" - self._running = False - if hasattr(self, '_processor_task') and not self._processor_task.done(): - self._processor_task.cancel() - logger.info("MessageManager processor task stopping.") - else: - logger.info("MessageManager processor task not running or already stopped.") - + """停止后台处理器任务。""" + self._running = False + if hasattr(self, "_processor_task") and not self._processor_task.done(): + self._processor_task.cancel() + logger.info("MessageManager processor task stopping.") + else: + logger.info("MessageManager processor task not running or already stopped.") async def get_container(self, chat_id: str) -> MessageContainer: """获取或创建聊天流的消息容器 (异步,使用锁)""" @@ -200,18 +200,18 @@ class MessageManager: chat_stream = message.chat_stream if not chat_stream: logger.error("消息缺少 chat_stream,无法添加到容器") - return # 或者抛出异常 + return # 或者抛出异常 container = await self.get_container(chat_stream.stream_id) container.add_message(message) def check_if_sending_message_exist(self, chat_id, thinking_id): """检查指定聊天流的容器中是否存在具有特定 thinking_id 的 MessageSending 消息 或 emoji 消息""" # 这个方法现在是非异步的,因为它只读取数据 - container = self.containers.get(chat_id) # 直接 get,因为读取不需要锁 + container = self.containers.get(chat_id) # 直接 get,因为读取不需要锁 if container and container.has_messages(): for message in container.get_all_messages(): if isinstance(message, MessageSending): - msg_id = getattr(message.message_info, 'message_id', None) + msg_id = getattr(message.message_info, "message_id", None) # 检查 message_id 是否匹配 thinking_id 或以 "me" 开头 (emoji) if msg_id == thinking_id or (msg_id and msg_id.startswith("me")): # logger.debug(f"检查到存在相同thinking_id或emoji的消息: {msg_id} for {thinking_id}") @@ -221,7 +221,7 @@ class MessageManager: async def _handle_sending_message(self, container: MessageContainer, message: MessageSending): """处理单个 MessageSending 消息 (包含 set_reply 逻辑)""" try: - _ = message.update_thinking_time() # 更新思考时间 + _ = message.update_thinking_time() # 更新思考时间 thinking_start_time = message.thinking_start_time now_time = time.time() thinking_messages_count, thinking_messages_length = count_messages_between( @@ -230,16 +230,18 @@ class MessageManager: # --- 条件应用 set_reply 逻辑 --- if ( - message.apply_set_reply_logic # 检查标记 + message.apply_set_reply_logic # 检查标记 and message.is_head and (thinking_messages_count > 4 or thinking_messages_length > 250) and not message.is_private_message() ): - logger.debug(f"[{message.chat_stream.stream_id}] 应用 set_reply 逻辑: {message.processed_plain_text[:20]}...") + logger.debug( + f"[{message.chat_stream.stream_id}] 应用 set_reply 逻辑: {message.processed_plain_text[:20]}..." + ) message.set_reply() # --- 结束条件 set_reply --- - await message.process() # 预处理消息内容 + await message.process() # 预处理消息内容 # 使用全局 message_sender 实例 await message_sender.send_message(message) @@ -250,22 +252,23 @@ class MessageManager: # logger.debug(f"[{message.chat_stream.stream_id}] Sent and removed message: {message.message_info.message_id}") except Exception as e: - logger.error(f"[{message.chat_stream.stream_id}] 处理发送消息 {getattr(message.message_info, 'message_id', 'N/A')} 时出错: {e}") + logger.error( + f"[{message.chat_stream.stream_id}] 处理发送消息 {getattr(message.message_info, 'message_id', 'N/A')} 时出错: {e}" + ) logger.exception("详细错误信息:") # 考虑是否移除出错的消息,防止无限循环 removed = container.remove_message(message) if removed: - logger.warning(f"[{message.chat_stream.stream_id}] 已移除处理出错的消息。") - + logger.warning(f"[{message.chat_stream.stream_id}] 已移除处理出错的消息。") async def _process_chat_messages(self, chat_id: str): """处理单个聊天流消息 (合并后的逻辑)""" - container = await self.get_container(chat_id) # 获取容器是异步的了 + container = await self.get_container(chat_id) # 获取容器是异步的了 if container.has_messages(): message_earliest = container.get_earliest_message() - if not message_earliest: # 如果最早消息为空,则退出 + if not message_earliest: # 如果最早消息为空,则退出 return if isinstance(message_earliest, MessageThinking): @@ -273,7 +276,7 @@ class MessageManager: message_earliest.update_thinking_time() thinking_time = message_earliest.thinking_time # 减少控制台刷新频率或只在时间显著变化时打印 - if int(thinking_time) % 5 == 0: # 每5秒打印一次 + if int(thinking_time) % 5 == 0: # 每5秒打印一次 print( f"消息 {message_earliest.message_info.message_id} 正在思考中,已思考 {int(thinking_time)} 秒\r", end="", @@ -282,9 +285,11 @@ class MessageManager: # 检查是否超时 if thinking_time > global_config.thinking_timeout: - logger.warning(f"[{chat_id}] 消息思考超时 ({thinking_time:.1f}秒),移除消息 {message_earliest.message_info.message_id}") + logger.warning( + f"[{chat_id}] 消息思考超时 ({thinking_time:.1f}秒),移除消息 {message_earliest.message_info.message_id}" + ) container.remove_message(message_earliest) - print() # 超时后换行,避免覆盖下一条日志 + print() # 超时后换行,避免覆盖下一条日志 elif isinstance(message_earliest, MessageSending): # --- 处理发送消息 --- @@ -300,7 +305,7 @@ class MessageManager: if msg is message_earliest: continue logger.info(f"[{chat_id}] 处理超时发送消息: {msg.message_info.message_id}") - await self._handle_sending_message(container, msg) # 复用处理逻辑 + await self._handle_sending_message(container, msg) # 复用处理逻辑 # 清理空容器 (可选) # async with self._container_lock: @@ -308,7 +313,6 @@ class MessageManager: # logger.debug(f"[{chat_id}] 容器已空,准备移除。") # del self.containers[chat_id] - async def _start_processor_loop(self): """消息处理器主循环""" while self._running: @@ -319,8 +323,8 @@ class MessageManager: chat_ids = list(self.containers.keys()) for chat_id in chat_ids: - # 为每个 chat_id 创建一个处理任务 - tasks.append(asyncio.create_task(self._process_chat_messages(chat_id))) + # 为每个 chat_id 创建一个处理任务 + tasks.append(asyncio.create_task(self._process_chat_messages(chat_id))) if tasks: try: @@ -331,13 +335,14 @@ class MessageManager: # 等待一小段时间,避免CPU空转 try: - await asyncio.sleep(0.1) # 稍微降低轮询频率 + await asyncio.sleep(0.1) # 稍微降低轮询频率 except asyncio.CancelledError: - logger.info("Processor loop sleep cancelled.") - break # 退出循环 + logger.info("Processor loop sleep cancelled.") + break # 退出循环 logger.info("MessageManager processor loop finished.") + # --- 创建全局实例 --- message_manager = MessageManager() message_sender = MessageSender() -# --- 结束全局实例 --- \ No newline at end of file +# --- 结束全局实例 --- diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index e79ff7d82..138a2f809 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -13,11 +13,12 @@ from src.plugins.models.utils_model import LLMRequest from src.config.config import global_config from src.plugins.chat.utils_image import image_path_to_base64 # Local import needed after move from src.plugins.utils.timer_calculater import Timer # <--- Import Timer + # --- Import necessary dependencies directly --- -from .heartFC_generator import ResponseGenerator # Assuming this is the type for gpt +from .heartFC_generator import ResponseGenerator # Assuming this is the type for gpt from src.do_tool.tool_use import ToolUser -from src.plugins.chat.emoji_manager import EmojiManager # Assuming this is the type -from ..chat.message_sender import message_manager # <-- Import the global manager +from src.plugins.chat.emoji_manager import EmojiManager # Assuming this is the type +from ..chat.message_sender import message_manager # <-- Import the global manager # --- End import --- @@ -37,7 +38,7 @@ if TYPE_CHECKING: # Keep this if HeartFCController methods are still needed elsewhere, # but the instance variable will be removed from HeartFChatting # from .heartFC_controler import HeartFCController - from src.heart_flow.heartflow import SubHeartflow, heartflow # <-- 同时导入 heartflow 实例用于类型检查 + from src.heart_flow.heartflow import SubHeartflow, heartflow # <-- 同时导入 heartflow 实例用于类型检查 PLANNER_TOOL_DEFINITION = [ { @@ -74,16 +75,17 @@ class HeartFChatting: 现在由其关联的 SubHeartflow 管理生命周期。 """ - def __init__(self, - chat_id: str, - # 显式依赖注入 - gpt_instance: ResponseGenerator, # 文本回复生成器 - tool_user_instance: ToolUser, # 工具使用实例 - emoji_manager_instance: EmojiManager, # 表情管理实例 - ): + def __init__( + self, + chat_id: str, + # 显式依赖注入 + gpt_instance: ResponseGenerator, # 文本回复生成器 + tool_user_instance: ToolUser, # 工具使用实例 + emoji_manager_instance: EmojiManager, # 表情管理实例 + ): """ HeartFChatting 初始化函数 - + 参数: chat_id: 聊天流唯一标识符(如stream_id) gpt_instance: 文本回复生成器实例 @@ -94,7 +96,7 @@ class HeartFChatting: self.stream_id: str = chat_id # 聊天流ID self.chat_stream: Optional[ChatStream] = None # 关联的聊天流 self.sub_hf: Optional[SubHeartflow] = None # 关联的子心流 - + # 初始化状态控制 self._initialized = False # 是否已初始化标志 self._init_lock = asyncio.Lock() # 初始化锁(确保只初始化一次) @@ -145,6 +147,7 @@ class HeartFChatting: # <-- 在这里导入 heartflow 实例 from src.heart_flow.heartflow import heartflow + self.sub_hf = heartflow.get_subheartflow(self.stream_id) if not self.sub_hf: logger.warning(f"{log_prefix} 获取SubHeartflow失败。一些功能可能受限。") @@ -391,7 +394,9 @@ class HeartFChatting: logger.info(f"{log_prefix} 等待新消息的 sleep 被中断。") raise # 重新抛出取消错误,以便外层循环处理 else: - logger.warning(f"{log_prefix} HeartFChatting: 无法获取 Observation 实例,无法等待新消息。") + logger.warning( + f"{log_prefix} HeartFChatting: 无法获取 Observation 实例,无法等待新消息。" + ) # --- 等待结束 --- elif action == "error": # Action specifically set to error by planner @@ -413,9 +418,7 @@ class HeartFChatting: timer_strings.append(f"{name}: {formatted_time}") if timer_strings: # 如果有有效计时器数据才打印 - logger.debug( - f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}" - ) + logger.debug(f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}") # --- Timer Decrement --- # cycle_duration = time.monotonic() - loop_cycle_start_time @@ -484,8 +487,12 @@ class HeartFChatting: self.sub_hf = heartflow.get_subheartflow(self.stream_id) if not self.sub_hf: logger.error(f"{log_prefix}[Planner] SubHeartflow is not available. Cannot proceed.") - return {"action": "error", "reasoning": "SubHeartflow unavailable", "llm_error": True, "observed_messages": []} - + return { + "action": "error", + "reasoning": "SubHeartflow unavailable", + "llm_error": True, + "observed_messages": [], + } try: # Access observation via self.sub_hf @@ -503,9 +510,7 @@ class HeartFChatting: # --- (Moved from _replier_work) 1. 思考前使用工具 --- # try: # Access tool_user directly - tool_result = await self.tool_user.use_tool( - message_txt=observed_messages_str, sub_heartflow=self.sub_hf - ) + tool_result = await self.tool_user.use_tool(message_txt=observed_messages_str, sub_heartflow=self.sub_hf) if tool_result.get("used_tools", False): tool_result_info = tool_result.get("structured_info", {}) logger.debug(f"{log_prefix}[Planner] 规划前工具结果: {tool_result_info}") @@ -620,7 +625,6 @@ class HeartFChatting: """ try: - # --- Create Placeholder --- # placeholder_id = f"mid_pf_{int(time.time() * 1000)}" placeholder_user = UserInfo( diff --git a/src/plugins/heartFC_chat/heartFC_generator.py b/src/plugins/heartFC_chat/heartFC_generator.py index b05764fd2..70d4109f8 100644 --- a/src/plugins/heartFC_chat/heartFC_generator.py +++ b/src/plugins/heartFC_chat/heartFC_generator.py @@ -11,6 +11,7 @@ from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager from ..utils.timer_calculater import Timer from src.plugins.moods.moods import MoodManager + # 定义日志配置 llm_config = LogConfig( # 使用消息发送专用样式 @@ -78,7 +79,6 @@ class ResponseGenerator: sender_name = f"<{message.chat_stream.user_info.platform}:{message.chat_stream.user_info.user_id}:{message.chat_stream.user_info.user_nickname}:{message.chat_stream.user_info.user_cardname}>" - with Timer() as t_build_prompt: prompt = await prompt_builder.build_prompt( build_mode="focus", @@ -86,7 +86,7 @@ class ResponseGenerator: current_mind_info=current_mind_info, message_txt=message.processed_plain_text, sender_name=sender_name, - chat_stream=message.chat_stream + chat_stream=message.chat_stream, ) logger.info(f"构建prompt时间: {t_build_prompt.human_readable}") diff --git a/src/plugins/heartFC_chat/heartflow_prompt_builder.py b/src/plugins/heartFC_chat/heartflow_prompt_builder.py index 086196ba8..53c4e575a 100644 --- a/src/plugins/heartFC_chat/heartflow_prompt_builder.py +++ b/src/plugins/heartFC_chat/heartflow_prompt_builder.py @@ -42,7 +42,7 @@ def init_prompt(): 涉及政治敏感以及违法违规的内容请规避。""", "moderation_prompt", ) - + Prompt( """ {relation_prompt_all} @@ -77,23 +77,18 @@ class PromptBuilder: self.prompt_built = "" self.activate_messages = "" - async def build_prompt( - self, build_mode,reason,current_mind_info, message_txt: str, sender_name: str = "某人",chat_stream=None + self, build_mode, reason, current_mind_info, message_txt: str, sender_name: str = "某人", chat_stream=None ) -> tuple[str, str]: - if build_mode == "normal": return await self._build_prompt_normal(chat_stream, message_txt, sender_name) - + elif build_mode == "focus": return await self._build_prompt_focus(reason, current_mind_info, chat_stream, message_txt, sender_name) - - async def _build_prompt_focus( self, reason, current_mind_info, chat_stream, message_txt: str, sender_name: str = "某人" ) -> tuple[str, str]: - individuality = Individuality.get_instance() prompt_personality = individuality.get_prompt(type="personality", x_person=2, level=1) prompt_identity = individuality.get_prompt(type="identity", x_person=2, level=1) @@ -104,14 +99,14 @@ class PromptBuilder: if chat_stream.group_info: chat_in_group = True else: - chat_in_group = False - + chat_in_group = False + message_list_before_now = get_raw_msg_before_timestamp_with_chat( - chat_id =chat_stream.stream_id, - timestamp = time.time(), + chat_id=chat_stream.stream_id, + timestamp=time.time(), limit=global_config.MAX_CONTEXT_SIZE, ) - + chat_talking_prompt = await build_readable_messages( message_list_before_now, replace_bot_name=True, @@ -147,7 +142,6 @@ class PromptBuilder: if random.random() < 0.02: prompt_ger += "你喜欢用反问句" - logger.debug("开始构建prompt") prompt = await global_prompt_manager.format_prompt( @@ -176,11 +170,7 @@ class PromptBuilder: return prompt - - - async def _build_prompt_normal( - self, chat_stream, message_txt: str, sender_name: str = "某人" - ) -> tuple[str, str]: + async def _build_prompt_normal(self, chat_stream, message_txt: str, sender_name: str = "某人") -> tuple[str, str]: # 开始构建prompt prompt_personality = "你" # person @@ -245,14 +235,14 @@ class PromptBuilder: if chat_stream.group_info: chat_in_group = True else: - chat_in_group = False - + chat_in_group = False + message_list_before_now = get_raw_msg_before_timestamp_with_chat( - chat_id =chat_stream.stream_id, - timestamp = time.time(), + chat_id=chat_stream.stream_id, + timestamp=time.time(), limit=global_config.MAX_CONTEXT_SIZE, ) - + chat_talking_prompt = await build_readable_messages( message_list_before_now, replace_bot_name=True, @@ -260,9 +250,7 @@ class PromptBuilder: timestamp_mode="relative", read_mark=0.0, ) - - - + # 关键词检测与反应 keywords_reaction_prompt = "" for rule in global_config.keywords_reaction_rules: @@ -303,11 +291,11 @@ class PromptBuilder: logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}秒") logger.debug("开始构建prompt") - - schedule_prompt=await global_prompt_manager.format_prompt( + + schedule_prompt = await global_prompt_manager.format_prompt( "schedule_prompt", schedule_info=bot_schedule.get_current_num_task(num=1, time_info=False) ) - + prompt = await global_prompt_manager.format_prompt( "reasoning_prompt_main", relation_prompt_all=await global_prompt_manager.get_prompt_async("relationship_prompt"), @@ -558,6 +546,5 @@ class PromptBuilder: return "\n".join(str(result["content"]) for result in results) - init_prompt() prompt_builder = PromptBuilder() diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index b37810be9..282e87b82 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -22,6 +22,7 @@ from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager from src.plugins.utils.timer_calculater import Timer from src.heart_flow.heartflow import heartflow from src.heart_flow.sub_heartflow import ChatState + # 定义日志配置 chat_config = LogConfig( console_format=CHAT_STYLE_CONFIG["console_format"], @@ -129,7 +130,7 @@ class NormalChat: is_head=not mark_head, is_emoji=False, thinking_start_time=thinking_start_time, - apply_set_reply_logic=True + apply_set_reply_logic=True, ) if not mark_head: mark_head = True @@ -165,7 +166,7 @@ class NormalChat: reply=message, is_head=False, is_emoji=True, - apply_set_reply_logic=True + apply_set_reply_logic=True, ) await message_manager.add_message(bot_message) @@ -212,13 +213,13 @@ class NormalChat: if removed_item: # logger.debug(f"[{stream_name}] 已从兴趣字典中移除消息 {msg_id} (因状态跳过)") # 减少日志 pass - continue # 处理下一条消息 + continue # 处理下一条消息 # --- 结束状态检查 --- # # --- 检查 HeartFChatting 是否活跃 (改为检查 SubHeartflow 状态) --- # is_focused = subheartflow.chat_state.chat_status == ChatState.FOCUSED - if is_focused: # New check: If the subflow is focused, NormalChat shouldn't process + if is_focused: # New check: If the subflow is focused, NormalChat shouldn't process removed_item = interest_dict.pop(msg_id, None) if removed_item: # logger.debug(f"[{stream_name}] SubHeartflow 处于 FOCUSED 状态,已跳过并移除 NormalChat 兴趣消息 {msg_id}") # Reduce noise @@ -264,7 +265,7 @@ class NormalChat: ) # 可以在这里添加 not_reply_handle 逻辑吗? 如果不回复,也需要清理意愿。 # 注意:willing_manager.setup 尚未调用 - willing_manager.setup(message, chat, is_mentioned, interested_rate) # 先 setup + willing_manager.setup(message, chat, is_mentioned, interested_rate) # 先 setup await willing_manager.not_reply_handle(message.message_info.message_id) willing_manager.delete(message.message_info.message_id) return @@ -313,7 +314,7 @@ class NormalChat: # 生成回复 sub_hf = heartflow.get_subheartflow(stream_id) - + try: with Timer("生成回复", timing_results): response_set = await self.gpt.generate_response( diff --git a/src/plugins/heartFC_chat/normal_chat_generator.py b/src/plugins/heartFC_chat/normal_chat_generator.py index 2fb07d318..82bfaffcc 100644 --- a/src/plugins/heartFC_chat/normal_chat_generator.py +++ b/src/plugins/heartFC_chat/normal_chat_generator.py @@ -9,6 +9,7 @@ from ..utils.timer_calculater import Timer from src.common.logger import get_module_logger, LogConfig, LLM_STYLE_CONFIG from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager from src.heart_flow.sub_heartflow import SubHeartflow + # 定义日志配置 llm_config = LogConfig( # 使用消息发送专用样式 @@ -40,7 +41,9 @@ class ResponseGenerator: self.current_model_type = "r1" # 默认使用 R1 self.current_model_name = "unknown model" - async def generate_response(self, sub_hf: SubHeartflow, message: MessageThinking, thinking_id: str) -> Optional[Union[str, List[str]]]: + async def generate_response( + self, sub_hf: SubHeartflow, message: MessageThinking, thinking_id: str + ) -> Optional[Union[str, List[str]]]: """根据当前模型类型选择对应的生成函数""" # 从global_config中获取模型概率值并选择模型 if random.random() < global_config.model_reasoning_probability: @@ -67,7 +70,9 @@ class ResponseGenerator: logger.info(f"{self.current_model_type}思考,失败") return None - async def _generate_response_with_model(self, sub_hf: SubHeartflow, message: MessageThinking, model: LLMRequest, thinking_id: str): + async def _generate_response_with_model( + self, sub_hf: SubHeartflow, message: MessageThinking, model: LLMRequest, thinking_id: str + ): info_catcher = info_catcher_manager.get_info_catcher(thinking_id) if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname: @@ -85,7 +90,7 @@ class ResponseGenerator: with Timer() as t_build_prompt: prompt = await prompt_builder.build_prompt( build_mode="normal", - reason= "", + reason="", current_mind_info="", message_txt=message.processed_plain_text, sender_name=sender_name, @@ -95,7 +100,7 @@ class ResponseGenerator: try: content, reasoning_content, self.current_model_name = await model.generate_response(prompt) - + logger.info(f"prompt:{prompt}\n生成回复:{content}") info_catcher.catch_after_llm_generated( @@ -108,7 +113,6 @@ class ResponseGenerator: return content - async def _get_emotion_tags(self, content: str, processed_plain_text: str): """提取情感标签,结合立场和情绪""" try: diff --git a/src/plugins/utils/chat_message_builder.py b/src/plugins/utils/chat_message_builder.py index d1dcdcf72..d822263db 100644 --- a/src/plugins/utils/chat_message_builder.py +++ b/src/plugins/utils/chat_message_builder.py @@ -246,7 +246,7 @@ async def _build_readable_messages_internal( if stripped_line.endswith("。"): stripped_line = stripped_line[:-1] output_lines.append(f"{stripped_line};") - output_lines.append("\n") # 在每个消息块后添加换行,保持可读性 + output_lines.append("\n") # 在每个消息块后添加换行,保持可读性 # 移除可能的多余换行,然后合并 formatted_string = "".join(output_lines).strip() @@ -314,5 +314,4 @@ async def build_readable_messages( return f"{read_mark_line}{formatted_after}" else: # 理论上不应该发生,但作为保险 - return read_mark_line.strip() # 如果前后都无消息,只返回标记行 - + return read_mark_line.strip() # 如果前后都无消息,只返回标记行