From 18778d2dc7296e6e3e2ea1a96b6c6fdbad4ab7b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 6 Jul 2025 12:17:38 +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/api/apiforgui.py | 1 - src/chat/focus_chat/focus_loop_info.py | 3 +- src/chat/focus_chat/heartFC_chat.py | 14 +++----- src/chat/focus_chat/hfc_utils.py | 1 - src/chat/heart_flow/chat_state_info.py | 1 + src/chat/heart_flow/heartflow.py | 4 +-- .../heart_flow/heartflow_message_processor.py | 1 + src/chat/planner_actions/action_modifier.py | 35 +++++++++---------- src/chat/planner_actions/planner_focus.py | 15 +++----- src/chat/utils/utils.py | 3 +- src/config/official_configs.py | 1 - 11 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/api/apiforgui.py b/src/api/apiforgui.py index 01685939e..058c6fc96 100644 --- a/src/api/apiforgui.py +++ b/src/api/apiforgui.py @@ -19,7 +19,6 @@ async def forced_change_subheartflow_status(subheartflow_id: str, status: ChatSt return False - async def get_all_states(): """获取所有状态""" all_states = await heartflow.api_get_all_states() diff --git a/src/chat/focus_chat/focus_loop_info.py b/src/chat/focus_chat/focus_loop_info.py index 2389f10c9..342368df7 100644 --- a/src/chat/focus_chat/focus_loop_info.py +++ b/src/chat/focus_chat/focus_loop_info.py @@ -76,7 +76,6 @@ class FocusLoopInfo: else: cycle_info_block = "\n" - # 获取history_loop中最新添加的 if self.history_loop: last_loop = self.history_loop[0] @@ -89,4 +88,4 @@ class FocusLoopInfo: else: cycle_info_block += f"距离你上一次阅读消息并思考和规划,已经过去了{time_diff}秒\n" else: - cycle_info_block += "你还没看过消息\n" \ No newline at end of file + cycle_info_block += "你还没看过消息\n" diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index ac95a984b..e0d679e0f 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -26,6 +26,7 @@ install(extra_lines=3) logger = get_logger("hfc") # Logger Name Changed + class HeartFChatting: """ 管理一个连续的Focus Chat循环 @@ -63,10 +64,7 @@ class HeartFChatting: self.loop_info: FocusLoopInfo = FocusLoopInfo(observe_id=self.stream_id) self.action_manager = ActionManager() - self.action_planner = ActionPlanner( - chat_id = self.stream_id, - action_manager=self.action_manager - ) + self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager) self.action_modifier = ActionModifier(action_manager=self.action_manager, chat_id=self.stream_id) self._processing_lock = asyncio.Lock() @@ -238,7 +236,6 @@ class HeartFChatting: self._current_cycle_detail.set_loop_info(loop_info) - self.loop_info.add_loop_info(self._current_cycle_detail) self._current_cycle_detail.timers = cycle_timers @@ -253,7 +250,6 @@ class HeartFChatting: formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒" timer_strings.append(f"{name}: {formatted_time}") - logger.info( f"{self.log_prefix} 第{self._current_cycle_detail.cycle_id}次思考," f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, " @@ -275,7 +271,7 @@ class HeartFChatting: self.performance_logger.record_cycle(cycle_performance_data) except Exception as perf_e: logger.warning(f"{self.log_prefix} 记录性能数据失败: {perf_e}") - + await asyncio.sleep(global_config.focus_chat.think_interval) except asyncio.CancelledError: @@ -352,7 +348,7 @@ class HeartFChatting: try: # 调用完整的动作修改流程 await self.action_modifier.modify_actions( - loop_info = self.loop_info, + loop_info=self.loop_info, mode="focus", ) except Exception as e: @@ -371,7 +367,7 @@ class HeartFChatting: plan_result.get("action_result", {}).get("action_data", {}), plan_result.get("action_result", {}).get("reasoning", "未提供理由"), ) - + action_data["loop_start_time"] = loop_start_time if action_type == "reply": diff --git a/src/chat/focus_chat/hfc_utils.py b/src/chat/focus_chat/hfc_utils.py index 7eeb9a7ab..11b04c801 100644 --- a/src/chat/focus_chat/hfc_utils.py +++ b/src/chat/focus_chat/hfc_utils.py @@ -104,7 +104,6 @@ class CycleDetail: self.loop_action_info = loop_info["loop_action_info"] - async def create_empty_anchor_message( platform: str, group_info: dict, chat_stream: ChatStream ) -> Optional[MessageRecv]: diff --git a/src/chat/heart_flow/chat_state_info.py b/src/chat/heart_flow/chat_state_info.py index 320093533..db4c2d5c7 100644 --- a/src/chat/heart_flow/chat_state_info.py +++ b/src/chat/heart_flow/chat_state_info.py @@ -7,6 +7,7 @@ class ChatState(enum.Enum): NORMAL = "随便水群" FOCUSED = "认真水群" + class ChatStateInfo: def __init__(self): self.chat_status: ChatState = ChatState.NORMAL diff --git a/src/chat/heart_flow/heartflow.py b/src/chat/heart_flow/heartflow.py index 7ab71fc39..f0e01e838 100644 --- a/src/chat/heart_flow/heartflow.py +++ b/src/chat/heart_flow/heartflow.py @@ -3,6 +3,7 @@ from src.common.logger import get_logger from typing import Any, Optional from typing import Dict from src.chat.message_receive.chat_stream import get_chat_manager + logger = get_logger("heartflow") @@ -36,12 +37,11 @@ class Heartflow: logger.error(f"创建子心流 {subheartflow_id} 失败: {e}", exc_info=True) return None - async def force_change_subheartflow_status(self, subheartflow_id: str, status: ChatState) -> None: """强制改变子心流的状态""" # 这里的 message 是可选的,可能是一个消息对象,也可能是其他类型的数据 return await self.force_change_state(subheartflow_id, status) - + async def force_change_state(self, subflow_id: Any, target_state: ChatState) -> bool: """强制改变指定子心流的状态""" subflow = self.subheartflows.get(subflow_id) diff --git a/src/chat/heart_flow/heartflow_message_processor.py b/src/chat/heart_flow/heartflow_message_processor.py index f68139058..66ddf362e 100644 --- a/src/chat/heart_flow/heartflow_message_processor.py +++ b/src/chat/heart_flow/heartflow_message_processor.py @@ -17,6 +17,7 @@ from src.person_info.relationship_manager import get_relationship_manager logger = get_logger("chat") + async def _process_relationship(message: MessageRecv) -> None: """处理用户关系逻辑 diff --git a/src/chat/planner_actions/action_modifier.py b/src/chat/planner_actions/action_modifier.py index 439558dd1..a2e0066cf 100644 --- a/src/chat/planner_actions/action_modifier.py +++ b/src/chat/planner_actions/action_modifier.py @@ -43,7 +43,7 @@ class ActionModifier: async def modify_actions( self, - loop_info = None, + loop_info=None, mode: str = "focus", message_content: str = "", ): @@ -60,10 +60,10 @@ class ActionModifier: removals_s1 = [] removals_s2 = [] - + self.action_manager.restore_actions() all_actions = self.action_manager.get_using_actions_for_mode(mode) - + message_list_before_now_half = get_raw_msg_before_timestamp_with_chat( chat_id=self.chat_stream.stream_id, timestamp=time.time(), @@ -77,7 +77,7 @@ class ActionModifier: read_mark=0.0, show_actions=True, ) - + if message_content: chat_content = chat_content + "\n" + f"现在,最新的消息是:{message_content}" @@ -99,14 +99,13 @@ class ActionModifier: self.action_manager.remove_action_from_using(action_name) logger.debug(f"{self.log_prefix}阶段一移除动作: {action_name},原因: {reason}") - # === 第二阶段:激活类型判定 === if chat_content is not None: logger.debug(f"{self.log_prefix}开始激活类型判定阶段") # 获取当前使用的动作集(经过第一阶段处理) current_using_actions = self.action_manager.get_using_actions_for_mode(mode) - + # 获取因激活类型判定而需要移除的动作 removals_s2 = await self._get_deactivated_actions_by_type( current_using_actions, @@ -118,7 +117,7 @@ class ActionModifier: for action_name, reason in removals_s2: self.action_manager.remove_action_from_using(action_name) logger.debug(f"{self.log_prefix}阶段二移除动作: {action_name},原因: {reason}") - + # === 统一日志记录 === all_removals = removals_s1 + removals_s2 if all_removals: @@ -136,11 +135,9 @@ class ActionModifier: associated_types_str = ", ".join(data["associated_types"]) reason = f"适配器不支持(需要: {associated_types_str})" type_mismatched_actions.append((action_name, reason)) - logger.debug( - f"{self.log_prefix}决定移除动作: {action_name},原因: {reason}" - ) + logger.debug(f"{self.log_prefix}决定移除动作: {action_name},原因: {reason}") return type_mismatched_actions - + async def _get_deactivated_actions_by_type( self, actions_with_info: Dict[str, Any], @@ -161,7 +158,7 @@ class ActionModifier: # 分类处理不同激活类型的actions llm_judge_actions = {} - + actions_to_check = list(actions_with_info.items()) random.shuffle(actions_to_check) @@ -188,7 +185,7 @@ class ActionModifier: elif activation_type == "llm_judge": llm_judge_actions[action_name] = action_info - + else: logger.warning(f"{self.log_prefix}未知的激活类型: {activation_type},跳过处理") @@ -512,21 +509,23 @@ class ActionModifier: # 如果最近sec_thres_reply_num次都是reply,40%概率移除 removal_probability = 0.4 / global_config.focus_chat.consecutive_replies if random.random() < removal_probability: - reason = f"连续回复较多(最近{sec_thres_reply_num}次全是reply,{removal_probability:.2f}概率移除,触发移除)" + reason = ( + f"连续回复较多(最近{sec_thres_reply_num}次全是reply,{removal_probability:.2f}概率移除,触发移除)" + ) removals.append(("reply", reason)) elif len(last_max_reply_num) >= one_thres_reply_num and all(last_max_reply_num[-one_thres_reply_num:]): # 如果最近one_thres_reply_num次都是reply,20%概率移除 removal_probability = 0.2 / global_config.focus_chat.consecutive_replies if random.random() < removal_probability: - reason = f"连续回复检测(最近{one_thres_reply_num}次全是reply,{removal_probability:.2f}概率移除,触发移除)" + reason = ( + f"连续回复检测(最近{one_thres_reply_num}次全是reply,{removal_probability:.2f}概率移除,触发移除)" + ) removals.append(("reply", reason)) else: logger.debug(f"{self.log_prefix}连续回复检测:无需移除reply动作,最近回复模式正常") return removals - - def get_available_actions_count(self) -> int: """获取当前可用动作数量(排除默认的no_action)""" current_actions = self.action_manager.get_using_actions_for_mode("normal") @@ -540,4 +539,4 @@ class ActionModifier: if available_count == 0: logger.debug(f"{self.log_prefix} 没有可用动作,跳过规划") return True - return False \ No newline at end of file + return False diff --git a/src/chat/planner_actions/planner_focus.py b/src/chat/planner_actions/planner_focus.py index 2aef5f429..0f5e84097 100644 --- a/src/chat/planner_actions/planner_focus.py +++ b/src/chat/planner_actions/planner_focus.py @@ -55,7 +55,7 @@ class ActionPlanner: def __init__(self, chat_id: str, action_manager: ActionManager): self.chat_id = chat_id self.log_prefix = f"[{get_chat_manager().get_stream_name(chat_id) or chat_id}]" - + self.action_manager = action_manager # LLM规划器配置 self.planner_llm = LLMRequest( @@ -67,7 +67,7 @@ class ActionPlanner: model=global_config.model.utils_small, request_type="focus.planner", # 用于动作规划 ) - + self.last_obs_time_mark = 0.0 async def plan(self) -> Dict[str, Any]: @@ -81,7 +81,7 @@ class ActionPlanner: try: is_group_chat = True - + message_list_before_now = get_raw_msg_before_timestamp_with_chat( chat_id=self.chat_id, timestamp=time.time(), @@ -95,7 +95,7 @@ class ActionPlanner: truncate=True, show_actions=True, ) - + self.last_obs_time_mark = time.time() # 获取聊天类型和目标信息 @@ -104,9 +104,7 @@ class ActionPlanner: try: # 重新获取更准确的聊天信息 is_group_chat, chat_target_info = get_chat_type_and_target_info(self.chat_id) - logger.debug( - f"{self.log_prefix}获取到聊天信息 - 群聊: {is_group_chat}, 目标信息: {chat_target_info}" - ) + logger.debug(f"{self.log_prefix}获取到聊天信息 - 群聊: {is_group_chat}, 目标信息: {chat_target_info}") except Exception as e: logger.warning(f"{self.log_prefix}获取聊天目标信息失败: {e}") chat_target_info = None @@ -201,7 +199,6 @@ class ActionPlanner: if key not in ["action", "reasoning"]: action_data[key] = value - if extracted_action not in current_available_actions: logger.warning( f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{extracted_action}' (可用: {list(current_available_actions.keys())}),将强制使用 'no_reply'" @@ -266,8 +263,6 @@ class ActionPlanner: action_options_block = "" for using_actions_name, using_actions_info in current_available_actions.items(): - - if using_actions_info["parameters"]: param_text = "\n" for param_name, param_description in using_actions_info["parameters"].items(): diff --git a/src/chat/utils/utils.py b/src/chat/utils/utils.py index d4bb5b17a..6bf776202 100644 --- a/src/chat/utils/utils.py +++ b/src/chat/utils/utils.py @@ -642,6 +642,7 @@ def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal" # 只返回时分秒格式,喵~ return time.strftime("%H:%M:%S", time.localtime(timestamp)) + def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Dict]]: """ 获取聊天类型(是否群聊)和私聊对象信息。 @@ -706,4 +707,4 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Dict]]: logger.error(f"获取聊天类型和目标信息时出错 for {chat_id}: {e}", exc_info=True) # Keep defaults on error - return is_group_chat, chat_target_info \ No newline at end of file + return is_group_chat, chat_target_info diff --git a/src/config/official_configs.py b/src/config/official_configs.py index a18f4a99b..335b95c77 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -300,7 +300,6 @@ class FocusChatConfig(ConfigBase): """连续回复能力,值越高,麦麦连续回复的概率越高""" - @dataclass class ExpressionConfig(ConfigBase): """表达配置类"""