From f9b95c8881be7a146622e8a5a5983c1c14ece37b Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Sat, 6 Sep 2025 10:08:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sleep):=20=E8=A7=A3=E8=80=A6ScheduleMa?= =?UTF-8?q?nager=E4=B8=8ESleepManager=EF=BC=8C=E5=BC=95=E5=85=A5=E6=A1=A5?= =?UTF-8?q?=E6=8E=A5=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为了降低模块间的耦合度并提升代码的可维护性,对睡眠管理系统进行了重构。 引入了`schedule_sleep_bridge`作为`ScheduleManager`和`SleepManager`之间的桥梁。`ScheduleManager`不再直接持有`SleepManager`的实例,而是通过桥接器更新其日程数据。`SleepManager`则通过桥接器获取所需的日程信息,实现了二者的解耦。 - **`ScheduleManager`**: 移除了所有与`SleepManager`直接交互的代码,现在只负责生成日程并通过桥接器发布。 - **`SleepManager`**: 构造函数和内部逻辑修改为依赖桥接器接口,而不是`ScheduleManager`实例。 - **`HeartFChatting`**: 更新了所有对睡眠状态管理的调用,使其通过新的`schedule_sleep_bridge`进行。 - **`DefaultReplyer`**: 采用了延迟导入的方式获取`schedule_manager`,减少了不必要的模块加载。 --- src/chat/chat_loop/heartFC_chat.py | 13 ++--- .../sleep_manager/schedule_bridge.py | 54 +++++++++++++++++++ .../chat_loop/sleep_manager/sleep_manager.py | 12 +++-- src/chat/replyer/default_generator.py | 2 +- src/schedule/schedule_manager.py | 21 ++------ 5 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 src/chat/chat_loop/sleep_manager/schedule_bridge.py diff --git a/src/chat/chat_loop/heartFC_chat.py b/src/chat/chat_loop/heartFC_chat.py index 037ad620e..cc86b245f 100644 --- a/src/chat/chat_loop/heartFC_chat.py +++ b/src/chat/chat_loop/heartFC_chat.py @@ -9,7 +9,8 @@ from src.common.logger import get_logger from src.config.config import global_config from src.person_info.relationship_builder_manager import relationship_builder_manager from src.chat.express.expression_learner import expression_learner_manager -from src.schedule.schedule_manager import schedule_manager, SleepState +from src.chat.chat_loop.sleep_manager.schedule_bridge import schedule_sleep_bridge +from src.chat.chat_loop.sleep_manager.sleep_manager import SleepState from src.plugin_system.apis import message_api from .hfc_context import HfcContext @@ -351,8 +352,8 @@ class HeartFChatting: - NORMAL模式:检查进入FOCUS模式的条件,并通过normal_mode_handler处理消息 """ # --- 核心状态更新 --- - await schedule_manager.update_sleep_state(self.wakeup_manager) - current_sleep_state = schedule_manager.get_current_sleep_state() + await schedule_sleep_bridge.update_sleep_state(self.wakeup_manager) + current_sleep_state = schedule_sleep_bridge.get_current_sleep_state() is_sleeping = current_sleep_state == SleepState.SLEEPING is_in_insomnia = current_sleep_state == SleepState.INSOMNIA @@ -382,7 +383,7 @@ class HeartFChatting: self._handle_wakeup_messages(recent_messages) # 再次获取最新状态,因为 handle_wakeup 可能导致状态变为 WOKEN_UP - current_sleep_state = schedule_manager.get_current_sleep_state() + current_sleep_state = schedule_sleep_bridge.get_current_sleep_state() if current_sleep_state == SleepState.SLEEPING: # 只有在纯粹的 SLEEPING 状态下才跳过消息处理 @@ -428,14 +429,14 @@ class HeartFChatting: # --- 重新入睡逻辑 --- # 如果被吵醒了,并且在一定时间内没有新消息,则尝试重新入睡 - if schedule_manager.get_current_sleep_state() == SleepState.WOKEN_UP and not has_new_messages: + if schedule_sleep_bridge.get_current_sleep_state() == SleepState.WOKEN_UP and not has_new_messages: re_sleep_delay = global_config.sleep_system.re_sleep_delay_minutes * 60 # 使用 last_message_time 来判断空闲时间 if time.time() - self.context.last_message_time > re_sleep_delay: logger.info( f"{self.context.log_prefix} 已被唤醒且超过 {re_sleep_delay / 60} 分钟无新消息,尝试重新入睡。" ) - schedule_manager.reset_sleep_state_after_wakeup() + schedule_sleep_bridge.reset_sleep_state_after_wakeup() # 保存HFC上下文状态 self.context.save_context_state() diff --git a/src/chat/chat_loop/sleep_manager/schedule_bridge.py b/src/chat/chat_loop/sleep_manager/schedule_bridge.py new file mode 100644 index 000000000..0ac15f2f5 --- /dev/null +++ b/src/chat/chat_loop/sleep_manager/schedule_bridge.py @@ -0,0 +1,54 @@ +# mmc/src/chat/chat_loop/sleep_manager/schedule_bridge.py + +""" +此模块充当 ScheduleManager 和 SleepManager 之间的桥梁, +将睡眠逻辑与日程生成逻辑解耦。 +""" + +from typing import Optional, TYPE_CHECKING, List, Dict, Any + +from .sleep_manager import SleepManager, SleepState + +if TYPE_CHECKING: + from src.chat.chat_loop.sleep_manager.wakeup_manager import WakeUpManager + + +class ScheduleSleepBridge: + def __init__(self): + # 桥接器现在持有 SleepManager 的唯一实例 + self.sleep_manager = SleepManager(self) + self.today_schedule: Optional[List[Dict[str, Any]]] = None + + def get_today_schedule(self) -> Optional[List[Dict[str, Any]]]: + """ + 向 SleepManager 提供当日日程。 + """ + return self.today_schedule + + def update_today_schedule(self, schedule: Optional[List[Dict[str, Any]]]): + """ + 由 ScheduleManager 调用以更新当日日程。 + """ + self.today_schedule = schedule + + # --- 代理方法,供应用程序的其他部分调用 --- + + def get_current_sleep_state(self) -> SleepState: + """从 SleepManager 获取当前的睡眠状态。""" + return self.sleep_manager.get_current_sleep_state() + + def is_sleeping(self) -> bool: + """检查当前是否处于正式休眠状态。""" + return self.sleep_manager.is_sleeping() + + async def update_sleep_state(self, wakeup_manager: Optional["WakeUpManager"] = None): + """更新睡眠状态机。""" + await self.sleep_manager.update_sleep_state(wakeup_manager) + + def reset_sleep_state_after_wakeup(self): + """被唤醒后,将状态切换到 WOKEN_UP。""" + self.sleep_manager.reset_sleep_state_after_wakeup() + + +# 创建一个全局可访问的桥接器单例 +schedule_sleep_bridge = ScheduleSleepBridge() \ No newline at end of file diff --git a/src/chat/chat_loop/sleep_manager/sleep_manager.py b/src/chat/chat_loop/sleep_manager/sleep_manager.py index 3acda568a..7c872c3b3 100644 --- a/src/chat/chat_loop/sleep_manager/sleep_manager.py +++ b/src/chat/chat_loop/sleep_manager/sleep_manager.py @@ -26,8 +26,8 @@ class SleepState(Enum): class SleepManager: - def __init__(self, schedule_manager): - self.schedule_manager = schedule_manager + def __init__(self, bridge): + self.bridge = bridge self.last_sleep_log_time = 0 self.sleep_log_interval = 35 # 日志记录间隔,单位秒 @@ -54,7 +54,8 @@ class SleepManager: 核心状态机:根据当前情况更新睡眠状态 """ # --- 基础检查 --- - if not global_config.sleep_system.enable or not self.schedule_manager.today_schedule: + today_schedule = self.bridge.get_today_schedule() + if not global_config.sleep_system.enable or not today_schedule: if self._current_state != SleepState.AWAKE: logger.debug("睡眠系统禁用或无日程,强制设为 AWAKE") self._current_state = SleepState.AWAKE @@ -218,8 +219,9 @@ class SleepManager: def _is_in_theoretical_sleep_time(self, now_time: time) -> tuple[bool, Optional[str]]: """检查当前时间是否落在日程表的任何一个睡眠活动中""" sleep_keywords = ["休眠", "睡觉", "梦乡"] - if self.schedule_manager.today_schedule: - for event in self.schedule_manager.today_schedule: + today_schedule = self.bridge.get_today_schedule() + if today_schedule: + for event in today_schedule: try: activity = event.get("activity", "").strip() time_range = event.get("time_range") diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index 20978f165..3874c2533 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -36,7 +36,6 @@ from src.person_info.relationship_fetcher import relationship_fetcher_manager from src.person_info.person_info import get_person_info_manager from src.plugin_system.base.component_types import ActionInfo, EventType from src.plugin_system.apis import llm_api -from src.schedule.schedule_manager import schedule_manager # 导入新的智能Prompt系统 from src.chat.utils.smart_prompt import SmartPrompt, SmartPromptParameters @@ -939,6 +938,7 @@ class DefaultReplyer: schedule_block = "" if global_config.schedule.enable: + from src.schedule.schedule_manager import schedule_manager current_activity = schedule_manager.get_current_activity() if current_activity: schedule_block = f"你当前正在:{current_activity}。" diff --git a/src/schedule/schedule_manager.py b/src/schedule/schedule_manager.py index e543eb706..058f1193a 100644 --- a/src/schedule/schedule_manager.py +++ b/src/schedule/schedule_manager.py @@ -15,7 +15,7 @@ from src.llm_models.utils_model import LLMRequest from src.common.logger import get_logger from json_repair import repair_json from src.manager.async_task_manager import AsyncTask, async_task_manager -from ..chat.chat_loop.sleep_manager.sleep_manager import SleepManager, SleepState +from ..chat.chat_loop.sleep_manager.schedule_bridge import schedule_sleep_bridge if TYPE_CHECKING: from src.chat.chat_loop.sleep_manager.wakeup_manager import WakeUpManager @@ -134,7 +134,6 @@ class ScheduleManager: self.max_retries = -1 # 无限重试,直到成功生成标准日程表 self.daily_task_started = False self.schedule_generation_running = False # 防止重复生成任务 - self.sleep_manager = SleepManager(self) async def start_daily_schedule_generation(self): """启动每日零点自动生成新日程的任务""" @@ -162,6 +161,7 @@ class ScheduleManager: schedule_data = orjson.loads(str(schedule_record.schedule_data)) if self._validate_schedule_with_pydantic(schedule_data): self.today_schedule = schedule_data + schedule_sleep_bridge.update_today_schedule(self.today_schedule) # 更新桥接器中的日程 schedule_str = f"已成功加载今天的日程 ({today_str}):\n" if self.today_schedule: for item in self.today_schedule: @@ -338,6 +338,7 @@ class ScheduleManager: logger.info(schedule_str) self.today_schedule = schedule_data + schedule_sleep_bridge.update_today_schedule(self.today_schedule) # 成功生成日程后,更新使用过的月度计划的统计信息 if used_plan_ids and global_config.monthly_plan_system: @@ -395,22 +396,6 @@ class ScheduleManager: continue return None - def get_current_sleep_state(self) -> SleepState: - """获取当前的睡眠状态""" - return self.sleep_manager.get_current_sleep_state() - - def is_sleeping(self) -> bool: - """检查当前是否处于正式休眠状态""" - return self.sleep_manager.is_sleeping() - - async def update_sleep_state(self, wakeup_manager: Optional["WakeUpManager"] = None): - """更新睡眠状态""" - await self.sleep_manager.update_sleep_state(wakeup_manager) - - def reset_sleep_state_after_wakeup(self): - """被唤醒后,将状态切换到 WOKEN_UP""" - self.sleep_manager.reset_sleep_state_after_wakeup() - def _validate_schedule_with_pydantic(self, schedule_data) -> bool: """使用Pydantic验证日程数据格式和完整性""" try: