diff --git a/.gitignore b/.gitignore index 0d6bfa6f7..18085f317 100644 --- a/.gitignore +++ b/.gitignore @@ -337,3 +337,4 @@ MaiBot.code-workspace /tests .kilocode/rules/MoFox.md src/chat/planner_actions/planner (2).py +rust_video/Cargo.lock diff --git a/src/chat/chat_loop/sleep_manager/time_checker.py b/src/chat/chat_loop/sleep_manager/time_checker.py index 342d0d62e..32521d408 100644 --- a/src/chat/chat_loop/sleep_manager/time_checker.py +++ b/src/chat/chat_loop/sleep_manager/time_checker.py @@ -1,5 +1,6 @@ -from datetime import datetime, time +from datetime import datetime, time, timedelta from typing import Optional +import random from src.common.logger import get_logger from src.config.config import global_config @@ -10,15 +11,37 @@ logger = get_logger("time_checker") class TimeChecker: def __init__(self, schedule_source): self.schedule_source = schedule_source + # 缓存当天的偏移量,确保一天内使用相同的偏移量 + self._daily_sleep_offset = None + self._daily_wake_offset = None + self._offset_date = None + + def _get_daily_offsets(self): + """获取当天的睡眠和起床时间偏移量,每天生成一次""" + today = datetime.now().date() + + # 如果是新的一天,重新生成偏移量 + if self._offset_date != today: + sleep_offset_range = global_config.sleep_system.sleep_time_offset_minutes + wake_offset_range = global_config.sleep_system.wake_up_time_offset_minutes + + # 生成 ±offset_range 范围内的随机偏移量 + self._daily_sleep_offset = random.randint(-sleep_offset_range, sleep_offset_range) + self._daily_wake_offset = random.randint(-wake_offset_range, wake_offset_range) + self._offset_date = today + + logger.debug(f"生成新的每日偏移量 - 睡觉时间偏移: {self._daily_sleep_offset}分钟, 起床时间偏移: {self._daily_wake_offset}分钟") + + return self._daily_sleep_offset, self._daily_wake_offset def is_in_theoretical_sleep_time(self, now_time: time) -> tuple[bool, Optional[str]]: if global_config.sleep_system.sleep_by_schedule: if self.schedule_source.get_today_schedule(): return self._is_in_schedule_sleep_time(now_time) else: - return self._is_in_fixed_sleep_time(now_time) + return self._is_in_sleep_time(now_time) else: - return self._is_in_fixed_sleep_time(now_time) + return self._is_in_sleep_time(now_time) def _is_in_schedule_sleep_time(self, now_time: time) -> tuple[bool, Optional[str]]: """检查当前时间是否落在日程表的任何一个睡眠活动中""" @@ -49,20 +72,33 @@ class TimeChecker: continue return False, None - def _is_in_fixed_sleep_time(self, now_time: time) -> tuple[bool, Optional[str]]: - """检查当前时间是否在固定的睡眠时间内""" + def _is_in_sleep_time(self, now_time: time) -> tuple[bool, Optional[str]]: + """检查当前时间是否在固定的睡眠时间内(应用偏移量)""" try: start_time_str = global_config.sleep_system.fixed_sleep_time end_time_str = global_config.sleep_system.fixed_wake_up_time - start_time = datetime.strptime(start_time_str, "%H:%M").time() - end_time = datetime.strptime(end_time_str, "%H:%M").time() + + # 获取当天的偏移量 + sleep_offset, wake_offset = self._get_daily_offsets() + + # 解析基础时间 + base_start_time = datetime.strptime(start_time_str, "%H:%M") + base_end_time = datetime.strptime(end_time_str, "%H:%M") + + # 应用偏移量 + actual_start_time = (base_start_time + timedelta(minutes=sleep_offset)).time() + actual_end_time = (base_end_time + timedelta(minutes=wake_offset)).time() + + logger.debug(f"固定睡眠时间检查 - 基础时间: {start_time_str}-{end_time_str}, " + f"偏移后时间: {actual_start_time.strftime('%H:%M')}-{actual_end_time.strftime('%H:%M')}, " + f"当前时间: {now_time.strftime('%H:%M')}") - if start_time <= end_time: - if start_time <= now_time < end_time: - return True, "固定睡眠时间" + if actual_start_time <= actual_end_time: + if actual_start_time <= now_time < actual_end_time: + return True, f"固定睡眠时间(偏移后: {actual_start_time.strftime('%H:%M')}-{actual_end_time.strftime('%H:%M')})" else: - if now_time >= start_time or now_time < end_time: - return True, "固定睡眠时间" + if now_time >= actual_start_time or now_time < actual_end_time: + return True, f"固定睡眠时间(偏移后: {actual_start_time.strftime('%H:%M')}-{actual_end_time.strftime('%H:%M')})" except ValueError as e: logger.error(f"固定的睡眠时间格式不正确,请使用 HH:MM 格式: {e}") return False, None \ No newline at end of file diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index f53b8ad99..3c71ef1d2 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -283,6 +283,7 @@ class DefaultReplyer: return False, None, None from src.plugin_system.core.event_manager import event_manager + # 触发 POST_LLM 事件(请求 LLM 之前) if not from_plugin: result = await event_manager.trigger_event( EventType.POST_LLM, plugin_name="SYSTEM", prompt=prompt, stream_id=stream_id @@ -304,6 +305,7 @@ class DefaultReplyer: "model": model_name, "tool_calls": tool_call, } + # 触发 AFTER_LLM 事件 if not from_plugin: result = await event_manager.trigger_event( diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 30d33006a..10bc3ae71 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -613,6 +613,8 @@ class SleepSystemConfig(ValidatedConfigBase): sleep_by_schedule: bool = Field(default=True, description="是否根据日程表进行睡觉") fixed_sleep_time: str = Field(default="23:00", description="固定的睡觉时间") fixed_wake_up_time: str = Field(default="07:00", description="固定的起床时间") + sleep_time_offset_minutes: int = Field(default=15, ge=0, le=60, description="睡觉时间随机偏移量范围(分钟),实际睡觉时间会在±该值范围内随机") + wake_up_time_offset_minutes: int = Field(default=15, ge=0, le=60, description="起床时间随机偏移量范围(分钟),实际起床时间会在±该值范围内随机") wakeup_threshold: float = Field(default=15.0, ge=1.0, description="唤醒阈值,达到此值时会被唤醒") private_message_increment: float = Field(default=3.0, ge=0.1, description="私聊消息增加的唤醒度") group_mention_increment: float = Field(default=2.0, ge=0.1, description="群聊艾特增加的唤醒度") diff --git a/src/plugins/built_in/set_typing_status/_manifest.json b/src/plugins/built_in/set_typing_status/_manifest.json index 0ba1ff237..45364c44a 100644 --- a/src/plugins/built_in/set_typing_status/_manifest.json +++ b/src/plugins/built_in/set_typing_status/_manifest.json @@ -1,4 +1,6 @@ { + + "manifest_version": 1, "name": "Set Typing Status", "description": "一个在LLM生成回复时设置私聊输入状态的插件。", "version": "1.0.0", diff --git a/src/plugins/built_in/set_typing_status/plugin.py b/src/plugins/built_in/set_typing_status/plugin.py index 5fe4c94e7..6eef98b19 100644 --- a/src/plugins/built_in/set_typing_status/plugin.py +++ b/src/plugins/built_in/set_typing_status/plugin.py @@ -29,7 +29,6 @@ class SetTypingStatusHandler(BaseEventHandler): user_id = message.message_info.user_info.user_id if not user_id: return HandlerResult(success=False, continue_process=True, message="无法获取用户ID") - try: params = {"user_id": user_id, "event_type": 1} await send_api.adapter_command_to_stream(