refactor(sleep): 解耦ScheduleManager与SleepManager,引入桥接模式

为了降低模块间的耦合度并提升代码的可维护性,对睡眠管理系统进行了重构。

引入了`schedule_sleep_bridge`作为`ScheduleManager`和`SleepManager`之间的桥梁。`ScheduleManager`不再直接持有`SleepManager`的实例,而是通过桥接器更新其日程数据。`SleepManager`则通过桥接器获取所需的日程信息,实现了二者的解耦。

- **`ScheduleManager`**: 移除了所有与`SleepManager`直接交互的代码,现在只负责生成日程并通过桥接器发布。
- **`SleepManager`**: 构造函数和内部逻辑修改为依赖桥接器接口,而不是`ScheduleManager`实例。
- **`HeartFChatting`**: 更新了所有对睡眠状态管理的调用,使其通过新的`schedule_sleep_bridge`进行。
- **`DefaultReplyer`**: 采用了延迟导入的方式获取`schedule_manager`,减少了不必要的模块加载。
This commit is contained in:
minecraft1024a
2025-09-06 10:08:31 +08:00
committed by Windpicker-owo
parent 31d30605b7
commit 7f2b965128
5 changed files with 72 additions and 30 deletions

View File

@@ -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()

View File

@@ -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()

View File

@@ -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")

View File

@@ -35,7 +35,6 @@ from src.mood.mood_manager import mood_manager
from src.person_info.person_info import Person, is_person_known
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
@@ -977,6 +976,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}"

View File

@@ -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: