refactor(schedule): 重构睡眠系统为状态机模型

将原有的睡眠、失眠、唤醒等分散的布尔标记逻辑重构为一个统一的睡眠状态机(SleepState),以提高代码的可读性、可维护性和可扩展性。

主要变更:
- 引入 `SleepState` 枚举,包含 `AWAKE`, `INSOMNIA`, `PREPARING_SLEEP`, `SLEEPING`, `WOKEN_UP` 状态。
- 在 `ScheduleManager` 中实现 `_update_sleep_state` 作为核心状态机,统一管理所有状态转换。
- 将原有的失眠判断逻辑从 `WakeUpManager` 移至 `ScheduleManager` 的状态机内部,与弹性睡眠决策合并,简化了模块职责。
- `heartFC_chat.py` 中的聊天循环现在直接查询 `ScheduleManager` 的当前状态,而不是处理多个独立的布尔值,使逻辑更清晰。
- 删除了 `WakeUpManager` 中与失眠相关的配置和方法,因为它现在由 `ScheduleManager` 统一管理。
- 删除了配置中已废弃的 `enable_is_sleep` 选项。
This commit is contained in:
minecraft1024a
2025-08-29 17:40:22 +08:00
parent 01455156a7
commit 41565eb144
4 changed files with 150 additions and 183 deletions

View File

@@ -8,7 +8,7 @@ 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.plugin_system.base.component_types import ChatMode
from src.schedule.schedule_manager import schedule_manager
from src.schedule.schedule_manager import schedule_manager, SleepState
from src.plugin_system.apis import message_api
from .hfc_context import HfcContext
@@ -196,30 +196,14 @@ class HeartFChatting:
- FOCUS模式直接处理所有消息并检查退出条件
- NORMAL模式检查进入FOCUS模式的条件并通过normal_mode_handler处理消息
"""
is_sleeping = schedule_manager.is_sleeping(self.wakeup_manager)
# --- 失眠状态管理 ---
if self.context.is_in_insomnia and time.time() > self.context.insomnia_end_time:
# 失眠状态结束
self.context.is_in_insomnia = False
await self.proactive_thinker.trigger_goodnight_thinking()
if is_sleeping and not self.context.was_sleeping:
# 刚刚进入睡眠状态,进行一次入睡检查
if self.wakeup_manager and self.wakeup_manager.check_for_insomnia():
# 触发失眠
self.context.is_in_insomnia = True
duration = global_config.sleep_system.insomnia_duration_minutes * 60
self.context.insomnia_end_time = time.time() + duration
# 判断失眠原因并触发思考
reason = "random"
if self.context.sleep_pressure < global_config.sleep_system.sleep_pressure_threshold:
reason = "low_pressure"
await self.proactive_thinker.trigger_insomnia_thinking(reason)
# --- 核心状态更新 ---
await schedule_manager._update_sleep_state(self.wakeup_manager)
current_sleep_state = schedule_manager.get_current_sleep_state()
is_sleeping = current_sleep_state == SleepState.SLEEPING
is_in_insomnia = current_sleep_state == SleepState.INSOMNIA
# 核心修复:在睡眠模式(包括失眠)下获取消息时,不过滤命令消息,以确保@消息能被接收
filter_command_flag = not is_sleeping
filter_command_flag = not (is_sleeping or is_in_insomnia)
recent_messages = message_api.get_messages_by_time_in_chat(
chat_id=self.context.stream_id,
@@ -239,16 +223,17 @@ class HeartFChatting:
self.context.last_read_time = time.time()
# 处理唤醒度逻辑
if is_sleeping:
if current_sleep_state in [SleepState.SLEEPING, SleepState.PREPARING_SLEEP, SleepState.INSOMNIA]:
self._handle_wakeup_messages(recent_messages)
# 再次检查睡眠状态因为_handle_wakeup_messages可能会触发唤醒
current_is_sleeping = schedule_manager.is_sleeping(self.wakeup_manager)
if not self.context.is_in_insomnia and current_is_sleeping:
# 仍然在睡眠,跳过本轮的消息处理
# 再次获取最新状态,因为 handle_wakeup 可能导致状态变为 WOKEN_UP
current_sleep_state = schedule_manager.get_current_sleep_state()
if current_sleep_state == SleepState.SLEEPING:
# 只有在纯粹的 SLEEPING 状态下才跳过消息处理
return has_new_messages
else:
# 从睡眠中被唤醒,需要继续处理本轮消息
if current_sleep_state == SleepState.WOKEN_UP:
logger.info(f"{self.context.log_prefix} 从睡眠中被唤醒,将处理积压的消息。")
self.context.last_wakeup_time = time.time()

View File

@@ -41,13 +41,6 @@ class WakeUpManager:
self.enabled = sleep_config.enable
self.angry_prompt = sleep_config.angry_prompt
# 失眠系统参数
self.insomnia_enabled = sleep_config.enable_insomnia_system
self.sleep_pressure_threshold = sleep_config.sleep_pressure_threshold
self.deep_sleep_threshold = sleep_config.deep_sleep_threshold
self.insomnia_chance_low_pressure = sleep_config.insomnia_chance_low_pressure
self.insomnia_chance_normal_pressure = sleep_config.insomnia_chance_normal_pressure
self._load_wakeup_state()
def _get_storage_key(self) -> str:
@@ -220,39 +213,4 @@ class WakeUpManager:
"wakeup_threshold": self.wakeup_threshold,
"is_angry": self.is_angry,
"angry_remaining_time": max(0, self.angry_duration - (time.time() - self.angry_start_time)) if self.is_angry else 0
}
def check_for_insomnia(self) -> bool:
"""
在尝试入睡时检查是否会失眠
Returns:
bool: 如果失眠则返回 True否则返回 False
"""
if not self.insomnia_enabled:
return False
import random
pressure = self.context.sleep_pressure
# 压力过高,深度睡眠,极难失眠
if pressure > self.deep_sleep_threshold:
return False
# 根据睡眠压力决定失眠概率
from src.schedule.schedule_manager import schedule_manager
if pressure < self.sleep_pressure_threshold:
# 压力不足型失眠
if schedule_manager._is_in_voluntary_delay:
logger.debug(f"{self.context.log_prefix} 处于主动延迟睡眠期间,跳过压力不足型失眠判断。")
elif random.random() < self.insomnia_chance_low_pressure:
logger.info(f"{self.context.log_prefix} 睡眠压力不足 ({pressure:.1f}),触发失眠!")
return True
else:
# 压力正常,随机失眠
if random.random() < self.insomnia_chance_normal_pressure:
logger.info(f"{self.context.log_prefix} 睡眠压力正常 ({pressure:.1f}),触发随机失眠!")
return True
return False
}