MaiBot/src/chat/heart_flow/mai_state_manager.py

136 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import enum
import time
import random
from typing import List, Tuple, Optional
from src.common.logger_manager import get_logger
from src.manager.mood_manager import mood_manager
logger = get_logger("mai_state")
class MaiState(enum.Enum):
"""
聊天状态:
OFFLINE: 不在线:回复概率极低,不会进行任何聊天
NORMAL_CHAT: 正常看手机:回复概率较高,会进行一些普通聊天和少量的专注聊天
FOCUSED_CHAT: 专注聊天:回复概率极高,会进行专注聊天和少量的普通聊天
"""
OFFLINE = "不在线"
NORMAL_CHAT = "正常看手机"
FOCUSED_CHAT = "专心看手机"
class MaiStateInfo:
def __init__(self):
self.mai_status: MaiState = MaiState.NORMAL_CHAT # 初始状态改为 NORMAL_CHAT
self.mai_status_history: List[Tuple[MaiState, float]] = [] # 历史状态,包含 状态,时间戳
self.last_status_change_time: float = time.time() # 状态最后改变时间
self.last_min_check_time: float = time.time() # 上次1分钟规则检查时间
# Mood management is now part of MaiStateInfo
self.mood_manager = mood_manager # Use singleton instance
def update_mai_status(self, new_status: MaiState) -> bool:
"""
更新聊天状态。
Args:
new_status: 新的 MaiState 状态。
Returns:
bool: 如果状态实际发生了改变则返回 True否则返回 False。
"""
if new_status != self.mai_status:
self.mai_status = new_status
current_time = time.time()
self.last_status_change_time = current_time
self.last_min_check_time = current_time # Reset 1-min check on any state change
self.mai_status_history.append((new_status, current_time))
logger.info(f"麦麦状态更新为: {self.mai_status.value}")
return True
else:
return False
def reset_state_timer(self):
"""
重置状态持续时间计时器和一分钟规则检查计时器。
通常在状态保持不变但需要重新开始计时的情况下调用(例如,保持 OFFLINE
"""
current_time = time.time()
self.last_status_change_time = current_time
self.last_min_check_time = current_time # Also reset the 1-min check timer
logger.debug("MaiStateInfo 状态计时器已重置。")
def get_mood_prompt(self) -> str:
"""获取当前的心情提示词"""
# Delegate to the internal mood manager
return self.mood_manager.get_mood_prompt()
def get_current_state(self) -> MaiState:
"""获取当前的 MaiState"""
return self.mai_status
class MaiStateManager:
"""管理 Mai 的整体状态转换逻辑"""
def __init__(self):
pass
@staticmethod
def check_and_decide_next_state(current_state_info: MaiStateInfo) -> Optional[MaiState]:
"""
根据当前状态和规则检查是否需要转换状态,并决定下一个状态。
"""
current_time = time.time()
current_status = current_state_info.mai_status
time_in_current_status = current_time - current_state_info.last_status_change_time
next_state: Optional[MaiState] = None
def _resolve_offline(candidate_state: MaiState) -> MaiState:
if candidate_state == MaiState.OFFLINE:
return current_status
return candidate_state
if current_status == MaiState.OFFLINE:
logger.info("当前[离线],没看手机,思考要不要上线看看......")
elif current_status == MaiState.NORMAL_CHAT:
logger.info("当前在[正常看手机]思考要不要继续聊下去......")
elif current_status == MaiState.FOCUSED_CHAT:
logger.info("当前在[专心看手机]思考要不要继续聊下去......")
if next_state is None:
time_limit_exceeded = False
choices_list = []
weights = []
rule_id = ""
if current_status == MaiState.OFFLINE:
return None
elif current_status == MaiState.NORMAL_CHAT:
if time_in_current_status >= 300: # NORMAL_CHAT 最多持续 300 秒
time_limit_exceeded = True
rule_id = "2.3 (From NORMAL_CHAT)"
weights = [100]
choices_list = [MaiState.FOCUSED_CHAT]
elif current_status == MaiState.FOCUSED_CHAT:
if time_in_current_status >= 600: # FOCUSED_CHAT 最多持续 600 秒
time_limit_exceeded = True
rule_id = "2.4 (From FOCUSED_CHAT)"
weights = [100]
choices_list = [MaiState.NORMAL_CHAT]
if time_limit_exceeded:
next_state_candidate = random.choices(choices_list, weights=weights, k=1)[0]
resolved_candidate = _resolve_offline(next_state_candidate)
logger.debug(
f"规则{rule_id}:时间到,切换到 {next_state_candidate.value}resolve 为 {resolved_candidate.value}"
)
next_state = resolved_candidate
if next_state is not None and next_state != current_status:
return next_state
else:
return None