修复代码格式和文件名大小写问题

This commit is contained in:
Windpicker-owo
2025-08-31 20:50:17 +08:00
parent a187130613
commit fe472dff60
213 changed files with 6897 additions and 8252 deletions

View File

@@ -16,11 +16,12 @@ from .cycle_tracker import CycleTracker
logger = get_logger("hfc.processor")
class CycleProcessor:
def __init__(self, context: HfcContext, response_handler: ResponseHandler, cycle_tracker: CycleTracker):
"""
初始化循环处理器
Args:
context: HFC聊天上下文对象包含聊天流、能量值等信息
response_handler: 响应处理器,负责生成和发送回复
@@ -30,18 +31,20 @@ class CycleProcessor:
self.response_handler = response_handler
self.cycle_tracker = cycle_tracker
self.action_planner = ActionPlanner(chat_id=self.context.stream_id, action_manager=self.context.action_manager)
self.action_modifier = ActionModifier(action_manager=self.context.action_manager, chat_id=self.context.stream_id)
self.action_modifier = ActionModifier(
action_manager=self.context.action_manager, chat_id=self.context.stream_id
)
async def observe(self, message_data: Optional[Dict[str, Any]] = None) -> bool:
"""
观察和处理单次思考循环的核心方法
Args:
message_data: 可选的消息数据字典,包含用户消息、平台信息等
Returns:
bool: 处理是否成功
功能说明:
- 开始新的思考循环并记录计时
- 修改可用动作并获取动作列表
@@ -51,15 +54,17 @@ class CycleProcessor:
"""
if not message_data:
message_data = {}
cycle_timers, thinking_id = self.cycle_tracker.start_cycle()
logger.info(f"{self.context.log_prefix} 开始第{self.context.cycle_counter}次思考[模式:{self.context.loop_mode}]")
logger.info(
f"{self.context.log_prefix} 开始第{self.context.cycle_counter}次思考[模式:{self.context.loop_mode}]"
)
if ENABLE_S4U:
await send_typing()
loop_start_time = time.time()
try:
await self.action_modifier.modify_actions()
available_actions = self.context.action_manager.get_using_actions()
@@ -68,15 +73,18 @@ class CycleProcessor:
available_actions = {}
is_mentioned_bot = message_data.get("is_mentioned", False)
at_bot_mentioned = (global_config.chat.mentioned_bot_inevitable_reply and is_mentioned_bot) or \
(global_config.chat.at_bot_inevitable_reply and is_mentioned_bot)
at_bot_mentioned = (global_config.chat.mentioned_bot_inevitable_reply and is_mentioned_bot) or (
global_config.chat.at_bot_inevitable_reply and is_mentioned_bot
)
if self.context.loop_mode == ChatMode.FOCUS and at_bot_mentioned and "no_reply" in available_actions:
available_actions = {k: v for k, v in available_actions.items() if k != "no_reply"}
skip_planner = False
if self.context.loop_mode == ChatMode.NORMAL:
non_reply_actions = {k: v for k, v in available_actions.items() if k not in ["reply", "no_reply", "no_action"]}
non_reply_actions = {
k: v for k, v in available_actions.items() if k not in ["reply", "no_reply", "no_action"]
}
if not non_reply_actions:
skip_planner = True
plan_result = self._get_direct_reply_plan(loop_start_time)
@@ -99,11 +107,14 @@ class CycleProcessor:
from src.plugin_system.core.event_manager import event_manager
from src.plugin_system.base.component_types import EventType
# 触发 ON_PLAN 事件
result = await event_manager.trigger_event(EventType.ON_PLAN, plugin_name="SYSTEM", stream_id=self.context.stream_id)
result = await event_manager.trigger_event(
EventType.ON_PLAN, plugin_name="SYSTEM", stream_id=self.context.stream_id
)
if result and not result.all_continue_process():
return
action_result = plan_result.get("action_result", {}) if isinstance(plan_result, dict) else {}
if not isinstance(action_result, dict):
action_result = {}
@@ -125,8 +136,16 @@ class CycleProcessor:
)
else:
await self._handle_other_actions(
action_type, reasoning, action_data, is_parallel, gen_task, target_message or message_data,
cycle_timers, thinking_id, plan_result, loop_start_time
action_type,
reasoning,
action_data,
is_parallel,
gen_task,
target_message or message_data,
cycle_timers,
thinking_id,
plan_result,
loop_start_time,
)
if ENABLE_S4U:
@@ -136,7 +155,7 @@ class CycleProcessor:
if self.context.energy_manager and global_config.sleep_system.enable_insomnia_system:
if action_type not in ["no_reply", "no_action"]:
self.context.energy_manager.increase_sleep_pressure()
return True
async def execute_plan(self, action_result: Dict[str, Any], target_message: Optional[Dict[str, Any]]):
@@ -144,7 +163,7 @@ class CycleProcessor:
执行一个已经制定好的计划
"""
action_type = action_result.get("action_type", "error")
# 这里我们需要为执行计划创建一个新的循环追踪
cycle_timers, thinking_id = self.cycle_tracker.start_cycle(is_proactive=True)
loop_start_time = time.time()
@@ -152,7 +171,9 @@ class CycleProcessor:
if action_type == "reply":
# 主动思考不应该直接触发简单回复但为了逻辑完整性我们假设它会调用response_handler
# 注意:这里的 available_actions 和 plan_result 是缺失的,需要根据实际情况处理
await self._handle_reply_action(target_message, {}, None, loop_start_time, cycle_timers, thinking_id, {"action_result": action_result})
await self._handle_reply_action(
target_message, {}, None, loop_start_time, cycle_timers, thinking_id, {"action_result": action_result}
)
else:
await self._handle_other_actions(
action_type,
@@ -164,13 +185,15 @@ class CycleProcessor:
cycle_timers,
thinking_id,
{"action_result": action_result},
loop_start_time
loop_start_time,
)
async def _handle_reply_action(self, message_data, available_actions, gen_task, loop_start_time, cycle_timers, thinking_id, plan_result):
async def _handle_reply_action(
self, message_data, available_actions, gen_task, loop_start_time, cycle_timers, thinking_id, plan_result
):
"""
处理回复类型的动作
Args:
message_data: 消息数据
available_actions: 可用动作列表
@@ -179,7 +202,7 @@ class CycleProcessor:
cycle_timers: 循环计时器
thinking_id: 思考ID
plan_result: 规划结果
功能说明:
- 根据聊天模式决定是否使用预生成的回复或实时生成
- 在NORMAL模式下使用异步生成提高效率
@@ -188,7 +211,7 @@ class CycleProcessor:
"""
# 初始化reply_to_str以避免UnboundLocalError
reply_to_str = None
if self.context.loop_mode == ChatMode.NORMAL:
if not gen_task:
reply_to_str = await self._build_reply_to_str(message_data)
@@ -204,7 +227,7 @@ class CycleProcessor:
# 如果gen_task已存在但reply_to_str还未构建需要构建它
if reply_to_str is None:
reply_to_str = await self._build_reply_to_str(message_data)
try:
response_set = await asyncio.wait_for(gen_task, timeout=global_config.chat.thinking_timeout)
except asyncio.TimeoutError:
@@ -224,10 +247,22 @@ class CycleProcessor:
)
self.cycle_tracker.end_cycle(loop_info, cycle_timers)
async def _handle_other_actions(self, action_type, reasoning, action_data, is_parallel, gen_task, action_message, cycle_timers, thinking_id, plan_result, loop_start_time):
async def _handle_other_actions(
self,
action_type,
reasoning,
action_data,
is_parallel,
gen_task,
action_message,
cycle_timers,
thinking_id,
plan_result,
loop_start_time,
):
"""
处理非回复类型的动作如no_reply、自定义动作等
Args:
action_type: 动作类型
reasoning: 动作理由
@@ -239,7 +274,7 @@ class CycleProcessor:
thinking_id: 思考ID
plan_result: 规划结果
loop_start_time: 循环开始时间
功能说明:
- 在NORMAL模式下可能并行执行回复生成和动作处理
- 等待所有异步任务完成
@@ -248,12 +283,18 @@ class CycleProcessor:
"""
background_reply_task = None
if self.context.loop_mode == ChatMode.NORMAL and is_parallel and gen_task:
background_reply_task = asyncio.create_task(self._handle_parallel_reply(gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result))
background_reply_task = asyncio.create_task(
self._handle_parallel_reply(
gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result
)
)
background_action_task = asyncio.create_task(self._handle_action(action_type, reasoning, action_data, cycle_timers, thinking_id, action_message))
background_action_task = asyncio.create_task(
self._handle_action(action_type, reasoning, action_data, cycle_timers, thinking_id, action_message)
)
reply_loop_info, action_success, action_reply_text, action_command = None, False, "", ""
if background_reply_task:
results = await asyncio.gather(background_reply_task, background_action_task, return_exceptions=True)
reply_result, action_result_val = results
@@ -261,7 +302,7 @@ class CycleProcessor:
reply_loop_info, _, _ = reply_result
else:
reply_loop_info = None
if not isinstance(action_result_val, BaseException) and action_result_val is not None:
action_success, action_reply_text, action_command = action_result_val
else:
@@ -272,19 +313,23 @@ class CycleProcessor:
action_result_val = results[0] # Get the actual result from the tuple
else:
action_result_val = (False, "", "")
if not isinstance(action_result_val, BaseException) and action_result_val is not None:
action_success, action_reply_text, action_command = action_result_val
else:
action_success, action_reply_text, action_command = False, "", ""
loop_info = self._build_final_loop_info(reply_loop_info, action_success, action_reply_text, action_command, plan_result)
loop_info = self._build_final_loop_info(
reply_loop_info, action_success, action_reply_text, action_command, plan_result
)
self.cycle_tracker.end_cycle(loop_info, cycle_timers)
async def _handle_parallel_reply(self, gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result):
async def _handle_parallel_reply(
self, gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result
):
"""
处理并行回复生成
Args:
gen_task: 回复生成任务
loop_start_time: 循环开始时间
@@ -292,10 +337,10 @@ class CycleProcessor:
cycle_timers: 循环计时器
thinking_id: 思考ID
plan_result: 规划结果
Returns:
tuple: (循环信息, 回复文本, 计时器信息) 或 None
功能说明:
- 等待并行回复生成任务完成(带超时)
- 构建回复目标字符串
@@ -306,7 +351,7 @@ class CycleProcessor:
response_set = await asyncio.wait_for(gen_task, timeout=global_config.chat.thinking_timeout)
except asyncio.TimeoutError:
return None, "", {}
if not response_set:
return None, "", {}
@@ -315,10 +360,12 @@ class CycleProcessor:
response_set, reply_to_str, loop_start_time, action_message, cycle_timers, thinking_id, plan_result
)
async def _handle_action(self, action, reasoning, action_data, cycle_timers, thinking_id, action_message) -> tuple[bool, str, str]:
async def _handle_action(
self, action, reasoning, action_data, cycle_timers, thinking_id, action_message
) -> tuple[bool, str, str]:
"""
处理具体的动作执行
Args:
action: 动作名称
reasoning: 执行理由
@@ -326,10 +373,10 @@ class CycleProcessor:
cycle_timers: 循环计时器
thinking_id: 思考ID
action_message: 动作消息
Returns:
tuple: (执行是否成功, 回复文本, 命令文本)
功能说明:
- 创建对应的动作处理器
- 执行动作并捕获异常
@@ -351,17 +398,17 @@ class CycleProcessor:
if not action_handler:
# 动作处理器创建失败,尝试回退机制
logger.warning(f"{self.context.log_prefix} 创建动作处理器失败: {action},尝试回退方案")
# 获取当前可用的动作
available_actions = self.context.action_manager.get_using_actions()
fallback_action = None
# 回退优先级reply > 第一个可用动作
if "reply" in available_actions:
fallback_action = "reply"
elif available_actions:
fallback_action = list(available_actions.keys())[0]
if fallback_action and fallback_action != action:
logger.info(f"{self.context.log_prefix} 使用回退动作: {fallback_action}")
action_handler = self.context.action_manager.create_action(
@@ -374,11 +421,11 @@ class CycleProcessor:
log_prefix=self.context.log_prefix,
action_message=action_message,
)
if not action_handler:
logger.error(f"{self.context.log_prefix} 回退方案也失败,无法创建任何动作处理器")
return False, "", ""
success, reply_text = await action_handler.handle_action()
return success, reply_text, ""
except Exception as e:
@@ -389,13 +436,13 @@ class CycleProcessor:
def _get_direct_reply_plan(self, loop_start_time):
"""
获取直接回复的规划结果
Args:
loop_start_time: 循环开始时间
Returns:
dict: 包含直接回复动作的规划结果
功能说明:
- 在某些情况下跳过复杂规划,直接返回回复动作
- 主要用于NORMAL模式下没有其他可用动作时的简化处理
@@ -414,21 +461,26 @@ class CycleProcessor:
async def _build_reply_to_str(self, message_data: dict):
"""
构建回复目标字符串
Args:
message_data: 消息数据字典
Returns:
str: 格式化的回复目标字符串,格式为"用户名:消息内容"
功能说明:
- 从消息数据中提取平台和用户ID信息
- 通过人员信息管理器获取用户昵称
- 构建用于回复显示的格式化字符串
"""
from src.person_info.person_info import get_person_info_manager
person_info_manager = get_person_info_manager()
platform = message_data.get("chat_info_platform") or message_data.get("user_platform") or (self.context.chat_stream.platform if self.context.chat_stream else "default")
platform = (
message_data.get("chat_info_platform")
or message_data.get("user_platform")
or (self.context.chat_stream.platform if self.context.chat_stream else "default")
)
user_id = message_data.get("user_id", "")
person_id = person_info_manager.get_person_id(platform, user_id)
person_name = await person_info_manager.get_value(person_id, "person_name")
@@ -437,17 +489,17 @@ class CycleProcessor:
def _build_final_loop_info(self, reply_loop_info, action_success, action_reply_text, action_command, plan_result):
"""
构建最终的循环信息
Args:
reply_loop_info: 回复循环信息可能为None
action_success: 动作执行是否成功
action_reply_text: 动作回复文本
action_command: 动作命令
plan_result: 规划结果
Returns:
dict: 完整的循环信息,包含规划信息和动作信息
功能说明:
- 如果有回复循环信息,则在其基础上添加动作信息
- 如果没有回复信息,则创建新的循环信息结构
@@ -455,11 +507,13 @@ class CycleProcessor:
"""
if reply_loop_info:
loop_info = reply_loop_info
loop_info["loop_action_info"].update({
"action_taken": action_success,
"command": action_command,
"taken_time": time.time(),
})
loop_info["loop_action_info"].update(
{
"action_taken": action_success,
"command": action_command,
"taken_time": time.time(),
}
)
else:
loop_info = {
"loop_plan_info": {"action_result": plan_result.get("action_result", {})},

View File

@@ -7,14 +7,15 @@ from .hfc_context import HfcContext
logger = get_logger("hfc")
class CycleTracker:
def __init__(self, context: HfcContext):
"""
初始化循环跟踪器
Args:
context: HFC聊天上下文对象
功能说明:
- 负责跟踪和记录每次思考循环的详细信息
- 管理循环的开始、结束和信息存储
@@ -24,13 +25,13 @@ class CycleTracker:
def start_cycle(self, is_proactive: bool = False) -> Tuple[Dict[str, float], str]:
"""
开始新的思考循环
Args:
is_proactive: 标记这个循环是否由主动思考发起
Returns:
tuple: (循环计时器字典, 思考ID字符串)
功能说明:
- 增加循环计数器
- 创建新的循环详情对象
@@ -39,7 +40,7 @@ class CycleTracker:
"""
if not is_proactive:
self.context.cycle_counter += 1
cycle_id = self.context.cycle_counter if not is_proactive else f"{self.context.cycle_counter}.p"
self.context.current_cycle_detail = CycleDetail(cycle_id)
self.context.current_cycle_detail.thinking_id = f"tid{str(round(time.time(), 2))}"
@@ -49,11 +50,11 @@ class CycleTracker:
def end_cycle(self, loop_info: Dict[str, Any], cycle_timers: Dict[str, float]):
"""
结束当前思考循环
Args:
loop_info: 循环信息,包含规划和动作信息
cycle_timers: 循环计时器,记录各阶段耗时
功能说明:
- 设置循环详情的完整信息
- 将当前循环加入历史记录
@@ -70,10 +71,10 @@ class CycleTracker:
def print_cycle_info(self, cycle_timers: Dict[str, float]):
"""
打印循环统计信息
Args:
cycle_timers: 循环计时器字典
功能说明:
- 格式化各阶段的耗时信息
- 计算总体循环持续时间
@@ -95,4 +96,4 @@ class CycleTracker:
f"耗时: {duration:.1f}秒, "
f"选择动作: {self.context.current_cycle_detail.loop_plan_info.get('action_result', {}).get('action_type', '未知动作')}"
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
)
)

View File

@@ -9,14 +9,15 @@ from src.schedule.schedule_manager import schedule_manager
logger = get_logger("hfc")
class EnergyManager:
def __init__(self, context: HfcContext):
"""
初始化能量管理器
Args:
context: HFC聊天上下文对象
功能说明:
- 管理聊天机器人的能量值系统
- 根据聊天模式自动调整能量消耗
@@ -30,7 +31,7 @@ class EnergyManager:
async def start(self):
"""
启动能量管理器
功能说明:
- 检查运行状态,避免重复启动
- 创建能量循环异步任务
@@ -45,7 +46,7 @@ class EnergyManager:
async def stop(self):
"""
停止能量管理器
功能说明:
- 取消正在运行的能量循环任务
- 等待任务完全停止
@@ -59,10 +60,10 @@ class EnergyManager:
def _handle_energy_completion(self, task: asyncio.Task):
"""
处理能量循环任务完成
Args:
task: 完成的异步任务对象
功能说明:
- 处理任务正常完成或异常情况
- 记录相应的日志信息
@@ -79,7 +80,7 @@ class EnergyManager:
async def _energy_loop(self):
"""
能量与睡眠压力管理的主循环
功能说明:
- 每10秒执行一次能量更新
- 根据群聊配置设置固定的聊天模式和能量值
@@ -120,16 +121,16 @@ class EnergyManager:
if self.context.loop_mode == ChatMode.FOCUS:
self.context.energy_value -= 0.6
self.context.energy_value = max(self.context.energy_value, 0.3)
self._log_energy_change("能量值衰减")
def _should_log_energy(self) -> bool:
"""
判断是否应该记录能量变化日志
Returns:
bool: 如果距离上次记录超过间隔时间则返回True
功能说明:
- 控制能量日志的记录频率,避免日志过于频繁
- 默认间隔90秒记录一次详细日志
@@ -147,17 +148,17 @@ class EnergyManager:
"""
increment = global_config.sleep_system.sleep_pressure_increment
self.context.sleep_pressure += increment
self.context.sleep_pressure = min(self.context.sleep_pressure, 100.0) # 设置一个100的上限
self.context.sleep_pressure = min(self.context.sleep_pressure, 100.0) # 设置一个100的上限
self._log_sleep_pressure_change("执行动作,睡眠压力累积")
def _log_energy_change(self, action: str, reason: str = ""):
"""
记录能量变化日志
Args:
action: 能量变化的动作描述
reason: 可选的变化原因
功能说明:
- 根据时间间隔决定使用info还是debug级别的日志
- 格式化能量值显示(保留一位小数)
@@ -166,12 +167,16 @@ class EnergyManager:
if self._should_log_energy():
log_message = f"{self.context.log_prefix} {action},当前能量值:{self.context.energy_value:.1f}"
if reason:
log_message = f"{self.context.log_prefix} {action}{reason},当前能量值:{self.context.energy_value:.1f}"
log_message = (
f"{self.context.log_prefix} {action}{reason},当前能量值:{self.context.energy_value:.1f}"
)
logger.info(log_message)
else:
log_message = f"{self.context.log_prefix} {action},当前能量值:{self.context.energy_value:.1f}"
if reason:
log_message = f"{self.context.log_prefix} {action}{reason},当前能量值:{self.context.energy_value:.1f}"
log_message = (
f"{self.context.log_prefix} {action}{reason},当前能量值:{self.context.energy_value:.1f}"
)
logger.debug(log_message)
def _log_sleep_pressure_change(self, action: str):
@@ -182,4 +187,4 @@ class EnergyManager:
if self._should_log_energy():
logger.info(f"{self.context.log_prefix} {action},当前睡眠压力:{self.context.sleep_pressure:.1f}")
else:
logger.debug(f"{self.context.log_prefix} {action},当前睡眠压力:{self.context.sleep_pressure:.1f}")
logger.debug(f"{self.context.log_prefix} {action},当前睡眠压力:{self.context.sleep_pressure:.1f}")

View File

@@ -22,14 +22,15 @@ from .wakeup_manager import WakeUpManager
logger = get_logger("hfc")
class HeartFChatting:
def __init__(self, chat_id: str):
"""
初始化心跳聊天管理器
Args:
chat_id: 聊天ID标识符
功能说明:
- 创建聊天上下文和所有子管理器
- 初始化循环跟踪器、响应处理器、循环处理器等核心组件
@@ -37,7 +38,7 @@ class HeartFChatting:
- 初始化聊天模式并记录初始化完成日志
"""
self.context = HfcContext(chat_id)
self.cycle_tracker = CycleTracker(self.context)
self.response_handler = ResponseHandler(self.context)
self.cycle_processor = CycleProcessor(self.context, self.response_handler, self.cycle_tracker)
@@ -45,20 +46,20 @@ class HeartFChatting:
self.proactive_thinker = ProactiveThinker(self.context, self.cycle_processor)
self.normal_mode_handler = NormalModeHandler(self.context, self.cycle_processor)
self.wakeup_manager = WakeUpManager(self.context)
# 将唤醒度管理器设置到上下文中
self.context.wakeup_manager = self.wakeup_manager
self.context.energy_manager = self.energy_manager
self._loop_task: Optional[asyncio.Task] = None
self._initialize_chat_mode()
logger.info(f"{self.context.log_prefix} HeartFChatting 初始化完成")
def _initialize_chat_mode(self):
"""
初始化聊天模式
功能说明:
- 检测是否为群聊环境
- 根据全局配置设置强制聊天模式
@@ -78,7 +79,7 @@ class HeartFChatting:
async def start(self):
"""
启动心跳聊天系统
功能说明:
- 检查是否已经在运行,避免重复启动
- 初始化关系构建器和表达学习器
@@ -89,14 +90,14 @@ class HeartFChatting:
if self.context.running:
return
self.context.running = True
self.context.relationship_builder = relationship_builder_manager.get_or_create_builder(self.context.stream_id)
self.context.expression_learner = expression_learner_manager.get_expression_learner(self.context.stream_id)
await self.energy_manager.start()
await self.proactive_thinker.start()
await self.wakeup_manager.start()
self._loop_task = asyncio.create_task(self._main_chat_loop())
self._loop_task.add_done_callback(self._handle_loop_completion)
logger.info(f"{self.context.log_prefix} HeartFChatting 启动完成")
@@ -104,7 +105,7 @@ class HeartFChatting:
async def stop(self):
"""
停止心跳聊天系统
功能说明:
- 检查是否正在运行,避免重复停止
- 设置运行状态为False
@@ -115,11 +116,11 @@ class HeartFChatting:
if not self.context.running:
return
self.context.running = False
await self.energy_manager.stop()
await self.proactive_thinker.stop()
await self.wakeup_manager.stop()
if self._loop_task and not self._loop_task.done():
self._loop_task.cancel()
await asyncio.sleep(0)
@@ -128,10 +129,10 @@ class HeartFChatting:
def _handle_loop_completion(self, task: asyncio.Task):
"""
处理主循环任务完成
Args:
task: 完成的异步任务对象
功能说明:
- 处理任务异常完成的情况
- 区分正常停止和异常终止
@@ -150,7 +151,7 @@ class HeartFChatting:
async def _main_chat_loop(self):
"""
主聊天循环
功能说明:
- 持续运行聊天处理循环
- 只有在有新消息时才进行思考循环
@@ -161,7 +162,7 @@ class HeartFChatting:
try:
while self.context.running:
has_new_messages = await self._loop_body()
if has_new_messages:
# 有新消息时,继续快速检查是否还有更多消息
await asyncio.sleep(1)
@@ -170,7 +171,7 @@ class HeartFChatting:
# 这里只是为了定期检查系统状态,不进行思考循环
# 真正的新消息响应依赖于消息到达时的通知
await asyncio.sleep(1.0)
except asyncio.CancelledError:
logger.info(f"{self.context.log_prefix} 麦麦已关闭聊天")
except Exception:
@@ -183,10 +184,10 @@ class HeartFChatting:
async def _loop_body(self) -> bool:
"""
单次循环体处理
Returns:
bool: 是否处理了新消息
功能说明:
- 检查是否处于睡眠模式,如果是则处理唤醒度逻辑
- 获取最近的新消息(过滤机器人自己的消息和命令)
@@ -204,7 +205,7 @@ class HeartFChatting:
# 核心修复:在睡眠模式(包括失眠)下获取消息时,不过滤命令消息,以确保@消息能被接收
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,
start_time=self.context.last_read_time,
@@ -214,25 +215,25 @@ class HeartFChatting:
filter_mai=True,
filter_command=filter_command_flag,
)
has_new_messages = bool(recent_messages)
# 只有在有新消息时才进行思考循环处理
if has_new_messages:
self.context.last_message_time = time.time()
self.context.last_read_time = time.time()
# 处理唤醒度逻辑
if current_sleep_state in [SleepState.SLEEPING, SleepState.PREPARING_SLEEP, SleepState.INSOMNIA]:
self._handle_wakeup_messages(recent_messages)
# 再次获取最新状态,因为 handle_wakeup 可能导致状态变为 WOKEN_UP
current_sleep_state = schedule_manager.get_current_sleep_state()
if current_sleep_state == SleepState.SLEEPING:
# 只有在纯粹的 SLEEPING 状态下才跳过消息处理
return has_new_messages
if current_sleep_state == SleepState.WOKEN_UP:
logger.info(f"{self.context.log_prefix} 从睡眠中被唤醒,将处理积压的消息。")
@@ -254,25 +255,27 @@ class HeartFChatting:
# 更新上一帧的睡眠状态
self.context.was_sleeping = is_sleeping
# --- 重新入睡逻辑 ---
# 如果被吵醒了,并且在一定时间内没有新消息,则尝试重新入睡
if schedule_manager.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} 分钟无新消息,尝试重新入睡。")
logger.info(
f"{self.context.log_prefix} 已被唤醒且超过 {re_sleep_delay / 60} 分钟无新消息,尝试重新入睡。"
)
schedule_manager.reset_sleep_state_after_wakeup()
# 保存HFC上下文状态
self.context.save_context_state()
return has_new_messages
def _check_focus_exit(self):
"""
检查是否应该退出FOCUS模式
功能说明:
- 区分私聊和群聊环境
- 在强制私聊focus模式下能量值低于1时重置为5但不退出
@@ -297,10 +300,10 @@ class HeartFChatting:
def _check_focus_entry(self, new_message_count: int):
"""
检查是否应该进入FOCUS模式
Args:
new_message_count: 新消息数量
功能说明:
- 区分私聊和群聊环境
- 强制私聊focus模式直接进入FOCUS模式并设置能量值为10
@@ -318,47 +321,51 @@ class HeartFChatting:
if is_group_chat and global_config.chat.group_chat_mode == "normal":
return
if global_config.chat.focus_value != 0: # 如果专注值配置不为0启用自动专注
if new_message_count > 3 / pow(global_config.chat.focus_value, 0.5): # 如果新消息数超过阈值(基于专注值计算)
if new_message_count > 3 / pow(
global_config.chat.focus_value, 0.5
): # 如果新消息数超过阈值(基于专注值计算)
self.context.loop_mode = ChatMode.FOCUS # 进入专注模式
self.context.energy_value = 10 + (new_message_count / (3 / pow(global_config.chat.focus_value, 0.5))) * 10 # 根据消息数量计算能量值
self.context.energy_value = (
10 + (new_message_count / (3 / pow(global_config.chat.focus_value, 0.5))) * 10
) # 根据消息数量计算能量值
return # 返回,不再检查其他条件
if self.context.energy_value >= 30: # 如果能量值达到或超过30
self.context.loop_mode = ChatMode.FOCUS # 进入专注模式
def _handle_wakeup_messages(self, messages):
"""
处理休眠状态下的消息,累积唤醒度
Args:
messages: 消息列表
功能说明:
- 区分私聊和群聊消息
- 检查群聊消息是否艾特了机器人
- 调用唤醒度管理器累积唤醒度
- 如果达到阈值则唤醒并进入愤怒状态
"""
if not self.wakeup_manager:
return
is_private_chat = self.context.chat_stream.group_info is None if self.context.chat_stream else False
for message in messages:
is_mentioned = False
# 检查群聊消息是否艾特了机器人
if not is_private_chat:
# 最终修复:直接使用消息对象中由上游处理好的 is_mention 字段。
# 该字段在 message.py 的 MessageRecv._process_single_segment 中被设置。
if message.get("is_mentioned"):
is_mentioned = True
# 累积唤醒度
woke_up = self.wakeup_manager.add_wakeup_value(is_private_chat, is_mentioned)
if woke_up:
logger.info(f"{self.context.log_prefix} 被消息吵醒,进入愤怒状态!")
break
"""
处理休眠状态下的消息,累积唤醒度
Args:
messages: 消息列表
功能说明:
- 区分私聊和群聊消息
- 检查群聊消息是否艾特了机器人
- 调用唤醒度管理器累积唤醒度
- 如果达到阈值则唤醒并进入愤怒状态
"""
if not self.wakeup_manager:
return
is_private_chat = self.context.chat_stream.group_info is None if self.context.chat_stream else False
for message in messages:
is_mentioned = False
# 检查群聊消息是否艾特了机器人
if not is_private_chat:
# 最终修复:直接使用消息对象中由上游处理好的 is_mention 字段。
# 该字段在 message.py 的 MessageRecv._process_single_segment 中被设置。
if message.get("is_mentioned"):
is_mentioned = True
# 累积唤醒度
woke_up = self.wakeup_manager.add_wakeup_value(is_private_chat, is_mentioned)
if woke_up:
logger.info(f"{self.context.log_prefix} 被消息吵醒,进入愤怒状态!")
break

View File

@@ -13,21 +13,22 @@ if TYPE_CHECKING:
from .wakeup_manager import WakeUpManager
from .energy_manager import EnergyManager
class HfcContext:
def __init__(self, chat_id: str):
"""
初始化HFC聊天上下文
Args:
chat_id: 聊天ID标识符
功能说明:
- 存储和管理单个聊天会话的所有状态信息
- 包含聊天流、关系构建器、表达学习器等核心组件
- 管理聊天模式、能量值、时间戳等关键状态
- 提供循环历史记录和当前循环详情的存储
- 集成唤醒度管理器,处理休眠状态下的唤醒机制
Raises:
ValueError: 如果找不到对应的聊天流
"""
@@ -37,29 +38,29 @@ class HfcContext:
raise ValueError(f"无法找到聊天流: {self.stream_id}")
self.log_prefix = f"[{get_chat_manager().get_stream_name(self.stream_id) or self.stream_id}]"
self.relationship_builder: Optional[RelationshipBuilder] = None
self.expression_learner: Optional[ExpressionLearner] = None
self.loop_mode = ChatMode.NORMAL
self.energy_value = 5.0
self.sleep_pressure = 0.0
self.was_sleeping = False # 用于检测睡眠状态的切换
self.was_sleeping = False # 用于检测睡眠状态的切换
self.last_message_time = time.time()
self.last_read_time = time.time() - 10
self.action_manager = ActionManager()
self.running: bool = False
self.history_loop: List[CycleDetail] = []
self.cycle_counter = 0
self.current_cycle_detail: Optional[CycleDetail] = None
# 唤醒度管理器 - 延迟初始化以避免循环导入
self.wakeup_manager: Optional['WakeUpManager'] = None
self.energy_manager: Optional['EnergyManager'] = None
self.wakeup_manager: Optional["WakeUpManager"] = None
self.energy_manager: Optional["EnergyManager"] = None
self._load_context_state()
@@ -87,4 +88,4 @@ class HfcContext:
}
local_storage[self._get_storage_key()] = state
logger = get_logger("hfc_context")
logger.debug(f"{self.log_prefix} 已将HFC上下文状态保存到本地存储: {state}")
logger.debug(f"{self.log_prefix} 已将HFC上下文状态保存到本地存储: {state}")

View File

@@ -15,7 +15,7 @@ logger = get_logger("hfc")
class CycleDetail:
"""
循环信息记录类
功能说明:
- 记录单次思考循环的详细信息
- 包含循环ID、思考ID、时间戳等基本信息
@@ -26,10 +26,10 @@ class CycleDetail:
def __init__(self, cycle_id: Union[int, str]):
"""
初始化循环详情记录
Args:
cycle_id: 循环ID用于标识循环的顺序
功能说明:
- 设置循环基本标识信息
- 初始化时间戳和计时器
@@ -47,10 +47,10 @@ class CycleDetail:
def to_dict(self) -> Dict[str, Any]:
"""
将循环信息转换为字典格式
Returns:
dict: 包含所有循环信息的字典,已处理循环引用和序列化问题
功能说明:
- 递归转换复杂对象为可序列化格式
- 防止循环引用导致的无限递归
@@ -111,10 +111,10 @@ class CycleDetail:
def set_loop_info(self, loop_info: Dict[str, Any]):
"""
设置循环信息
Args:
loop_info: 包含循环规划和动作信息的字典
功能说明:
- 从传入的循环信息中提取规划和动作信息
- 更新当前循环详情的相关字段
@@ -126,14 +126,14 @@ class CycleDetail:
def get_recent_message_stats(minutes: float = 30, chat_id: Optional[str] = None) -> dict:
"""
获取最近消息统计信息
Args:
minutes: 检索的分钟数默认30分钟
chat_id: 指定的chat_id仅统计该chat下的消息。为None时统计全部
Returns:
dict: {"bot_reply_count": int, "total_message_count": int}
功能说明:
- 统计指定时间范围内的消息数量
- 区分机器人回复和总消息数
@@ -162,7 +162,7 @@ def get_recent_message_stats(minutes: float = 30, chat_id: Optional[str] = None)
async def send_typing():
"""
发送打字状态指示
功能说明:
- 创建内心聊天流(用于状态显示)
- 发送typing状态消息
@@ -181,10 +181,11 @@ async def send_typing():
message_type="state", content="typing", stream_id=chat.stream_id, storage_message=False
)
async def stop_typing():
"""
停止打字状态指示
功能说明:
- 创建内心聊天流(用于状态显示)
- 发送stop_typing状态消息
@@ -201,4 +202,4 @@ async def stop_typing():
await send_api.custom_to_stream(
message_type="state", content="stop_typing", stream_id=chat.stream_id, storage_message=False
)
)

View File

@@ -11,15 +11,16 @@ if TYPE_CHECKING:
logger = get_logger("hfc.normal_mode")
class NormalModeHandler:
def __init__(self, context: HfcContext, cycle_processor: "CycleProcessor"):
"""
初始化普通模式处理器
Args:
context: HFC聊天上下文对象
cycle_processor: 循环处理器,用于处理决定回复的消息
功能说明:
- 处理NORMAL模式下的消息
- 根据兴趣度和回复概率决定是否回复
@@ -32,13 +33,13 @@ class NormalModeHandler:
async def handle_message(self, message_data: Dict[str, Any]) -> bool:
"""
处理NORMAL模式下的单条消息
Args:
message_data: 消息数据字典,包含用户信息、消息内容、兴趣值等
Returns:
bool: 是否进行了回复处理
功能说明:
- 计算消息的兴趣度和基础回复概率
- 应用谈话频率调整回复概率
@@ -80,4 +81,4 @@ class NormalModeHandler:
return True
self.willing_manager.delete(message_data.get("message_id", ""))
return False
return False

View File

@@ -13,15 +13,16 @@ if TYPE_CHECKING:
logger = get_logger("hfc")
class ProactiveThinker:
def __init__(self, context: HfcContext, cycle_processor: "CycleProcessor"):
"""
初始化主动思考器
Args:
context: HFC聊天上下文对象
cycle_processor: 循环处理器,用于执行主动思考的结果
功能说明:
- 管理机器人的主动发言功能
- 根据沉默时间和配置触发主动思考
@@ -31,7 +32,7 @@ class ProactiveThinker:
self.context = context
self.cycle_processor = cycle_processor
self._proactive_thinking_task: Optional[asyncio.Task] = None
self.proactive_thinking_prompts = {
"private": """现在你和你朋友的私聊里面已经隔了{time}没有发送消息了,请你结合上下文以及你和你朋友之前聊过的话题和你的人设来决定要不要主动发送消息,你可以选择:
@@ -50,7 +51,7 @@ class ProactiveThinker:
async def start(self):
"""
启动主动思考器
功能说明:
- 检查运行状态和配置,避免重复启动
- 只有在启用主动思考功能时才启动
@@ -66,7 +67,7 @@ class ProactiveThinker:
async def stop(self):
"""
停止主动思考器
功能说明:
- 取消正在运行的主动思考任务
- 等待任务完全停止
@@ -80,10 +81,10 @@ class ProactiveThinker:
def _handle_proactive_thinking_completion(self, task: asyncio.Task):
"""
处理主动思考任务完成
Args:
task: 完成的异步任务对象
功能说明:
- 处理任务正常完成或异常情况
- 记录相应的日志信息
@@ -100,7 +101,7 @@ class ProactiveThinker:
async def _proactive_thinking_loop(self):
"""
主动思考的主循环
功能说明:
- 每15秒检查一次是否需要主动思考
- 只在FOCUS模式下进行主动思考
@@ -114,7 +115,7 @@ class ProactiveThinker:
if self.context.loop_mode != ChatMode.FOCUS:
continue
if not self._should_enable_proactive_thinking():
continue
@@ -122,7 +123,7 @@ class ProactiveThinker:
silence_duration = current_time - self.context.last_message_time
target_interval = self._get_dynamic_thinking_interval()
if silence_duration >= target_interval:
try:
await self._execute_proactive_thinking(silence_duration)
@@ -130,14 +131,14 @@ class ProactiveThinker:
except Exception as e:
logger.error(f"{self.context.log_prefix} 主动思考执行出错: {e}")
logger.error(traceback.format_exc())
def _should_enable_proactive_thinking(self) -> bool:
"""
检查是否应该启用主动思考
Returns:
bool: 如果应该启用主动思考则返回True
功能说明:
- 检查聊天流是否存在
- 检查当前聊天是否在启用列表中(按平台和类型分别检查)
@@ -149,15 +150,15 @@ class ProactiveThinker:
return False
is_group_chat = self.context.chat_stream.group_info is not None
# 检查基础开关
if is_group_chat and not global_config.chat.proactive_thinking_in_group:
return False
if not is_group_chat and not global_config.chat.proactive_thinking_in_private:
return False
# 获取当前聊天的完整标识 (platform:chat_id)
stream_parts = self.context.stream_id.split(':')
stream_parts = self.context.stream_id.split(":")
if len(stream_parts) >= 2:
platform = stream_parts[0]
chat_id = stream_parts[1]
@@ -165,28 +166,28 @@ class ProactiveThinker:
else:
# 如果无法解析则使用原始stream_id
current_chat_identifier = self.context.stream_id
# 检查是否在启用列表中
if is_group_chat:
# 群聊检查
enable_list = getattr(global_config.chat, 'proactive_thinking_enable_in_groups', [])
enable_list = getattr(global_config.chat, "proactive_thinking_enable_in_groups", [])
if enable_list and current_chat_identifier not in enable_list:
return False
else:
# 私聊检查
enable_list = getattr(global_config.chat, 'proactive_thinking_enable_in_private', [])
# 私聊检查
enable_list = getattr(global_config.chat, "proactive_thinking_enable_in_private", [])
if enable_list and current_chat_identifier not in enable_list:
return False
return True
def _get_dynamic_thinking_interval(self) -> float:
"""
获取动态思考间隔
Returns:
float: 计算得出的思考间隔时间(秒)
功能说明:
- 使用3-sigma规则计算正态分布的思考间隔
- 基于base_interval和delta_sigma配置计算
@@ -196,15 +197,15 @@ class ProactiveThinker:
"""
try:
from src.utils.timing_utils import get_normal_distributed_interval
base_interval = global_config.chat.proactive_thinking_interval
delta_sigma = getattr(global_config.chat, 'delta_sigma', 120)
delta_sigma = getattr(global_config.chat, "delta_sigma", 120)
if base_interval < 0:
base_interval = abs(base_interval)
if delta_sigma < 0:
delta_sigma = abs(delta_sigma)
if base_interval == 0 and delta_sigma == 0:
return 300
elif base_interval == 0:
@@ -212,27 +213,27 @@ class ProactiveThinker:
return get_normal_distributed_interval(0, sigma_percentage, 1, 86400, use_3sigma_rule=True)
elif delta_sigma == 0:
return base_interval
sigma_percentage = delta_sigma / base_interval
return get_normal_distributed_interval(base_interval, sigma_percentage, 1, 86400, use_3sigma_rule=True)
except ImportError:
logger.warning(f"{self.context.log_prefix} timing_utils不可用使用固定间隔")
return max(300, abs(global_config.chat.proactive_thinking_interval))
except Exception as e:
logger.error(f"{self.context.log_prefix} 动态间隔计算出错: {e},使用固定间隔")
return max(300, abs(global_config.chat.proactive_thinking_interval))
def _format_duration(self, seconds: float) -> str:
"""
格式化持续时间为中文描述
Args:
seconds: 持续时间(秒)
Returns:
str: 格式化后的时间字符串,如"1小时30分45秒"
功能说明:
- 将秒数转换为小时、分钟、秒的组合
- 只显示非零的时间单位
@@ -256,7 +257,7 @@ class ProactiveThinker:
async def _execute_proactive_thinking(self, silence_duration: float):
"""
执行主动思考
Args:
silence_duration: 沉默持续时间(秒)
"""
@@ -265,12 +266,16 @@ class ProactiveThinker:
try:
# 直接调用 planner 的 PROACTIVE 模式
action_result_tuple, target_message = await self.cycle_processor.action_planner.plan(mode=ChatMode.PROACTIVE)
action_result_tuple, target_message = await self.cycle_processor.action_planner.plan(
mode=ChatMode.PROACTIVE
)
action_result = action_result_tuple.get("action_result")
# 如果决策不是 do_nothing则执行
if action_result and action_result.get("action_type") != "do_nothing":
logger.info(f"{self.context.log_prefix} 主动思考决策: {action_result.get('action_type')}, 原因: {action_result.get('reasoning')}")
logger.info(
f"{self.context.log_prefix} 主动思考决策: {action_result.get('action_type')}, 原因: {action_result.get('reasoning')}"
)
# 将决策结果交给 cycle_processor 的后续流程处理
await self.cycle_processor.execute_plan(action_result, target_message)
else:
@@ -283,21 +288,22 @@ class ProactiveThinker:
async def trigger_insomnia_thinking(self, reason: str):
"""
由外部事件(如失眠)触发的一次性主动思考
Args:
reason: 触发的原因 (e.g., "low_pressure", "random")
"""
logger.info(f"{self.context.log_prefix} 因“{reason}”触发失眠,开始深夜思考...")
# 1. 根据原因修改情绪
try:
from src.mood.mood_manager import mood_manager
mood_obj = mood_manager.get_mood_by_chat_id(self.context.stream_id)
if reason == "low_pressure":
mood_obj.mood_state = "精力过剩,毫无睡意"
elif reason == "random":
mood_obj.mood_state = "深夜emo胡思乱想"
mood_obj.last_change_time = time.time() # 更新时间戳以允许后续的情绪回归
mood_obj.last_change_time = time.time() # 更新时间戳以允许后续的情绪回归
logger.info(f"{self.context.log_prefix} 因失眠,情绪状态被强制更新为: {mood_obj.mood_state}")
except Exception as e:
logger.error(f"{self.context.log_prefix} 设置失眠情绪时出错: {e}")
@@ -315,10 +321,11 @@ class ProactiveThinker:
在失眠状态结束后,触发一次准备睡觉的主动思考
"""
logger.info(f"{self.context.log_prefix} 失眠状态结束,准备睡觉,触发告别思考...")
# 1. 设置一个准备睡觉的特定情绪
try:
from src.mood.mood_manager import mood_manager
mood_obj = mood_manager.get_mood_by_chat_id(self.context.stream_id)
mood_obj.mood_state = "有点困了,准备睡觉了"
mood_obj.last_change_time = time.time()

View File

@@ -17,14 +17,15 @@ from src.chat.utils.prompt_builder import Prompt
logger = get_logger("hfc")
anti_injector_logger = get_logger("anti_injector")
class ResponseHandler:
def __init__(self, context: HfcContext):
"""
初始化响应处理器
Args:
context: HFC聊天上下文对象
功能说明:
- 负责生成和发送机器人的回复
- 处理回复的格式化和发送逻辑
@@ -44,7 +45,7 @@ class ResponseHandler:
) -> Tuple[Dict[str, Any], str, Dict[str, float]]:
"""
生成并发送回复的主方法
Args:
response_set: 生成的回复内容集合
reply_to_str: 回复目标字符串
@@ -53,10 +54,10 @@ class ResponseHandler:
cycle_timers: 循环计时器
thinking_id: 思考ID
plan_result: 规划结果
Returns:
tuple: (循环信息, 回复文本, 计时器信息)
功能说明:
- 发送生成的回复内容
- 存储动作信息到数据库
@@ -66,11 +67,13 @@ class ResponseHandler:
reply_text = await self._send_response(response_set, reply_to_str, loop_start_time, action_message)
person_info_manager = get_person_info_manager()
platform = "default"
if self.context.chat_stream:
platform = (
action_message.get("chat_info_platform") or action_message.get("user_platform") or self.context.chat_stream.platform
action_message.get("chat_info_platform")
or action_message.get("user_platform")
or self.context.chat_stream.platform
)
user_id = action_message.get("user_id", "")
@@ -105,16 +108,16 @@ class ResponseHandler:
async def _send_response(self, reply_set, reply_to, thinking_start_time, message_data) -> str:
"""
发送回复内容的具体实现
Args:
reply_set: 回复内容集合,包含多个回复段
reply_to: 回复目标
thinking_start_time: 思考开始时间
message_data: 消息数据
Returns:
str: 完整的回复文本
功能说明:
- 检查是否有新消息需要回复
- 处理主动思考的"沉默"决定
@@ -139,14 +142,14 @@ class ResponseHandler:
for reply_seg in reply_set:
# 调试日志验证reply_seg的格式
logger.debug(f"Processing reply_seg type: {type(reply_seg)}, content: {reply_seg}")
# 修正:正确处理元组格式 (格式为: (type, content))
if isinstance(reply_seg, tuple) and len(reply_seg) >= 2:
_, data = reply_seg
else:
# 向下兼容:如果已经是字符串,则直接使用
data = str(reply_seg)
reply_text += data
if is_proactive_thinking and data.strip() == "沉默":
@@ -189,16 +192,16 @@ class ResponseHandler:
) -> Optional[list]:
"""
生成回复内容
Args:
message_data: 消息数据
available_actions: 可用动作列表
reply_to: 回复目标
request_type: 请求类型,默认为普通回复
Returns:
list: 生成的回复内容列表失败时返回None
功能说明:
- 在生成回复前进行反注入检测(提高效率)
- 调用生成器API生成回复
@@ -213,12 +216,10 @@ class ResponseHandler:
result, modified_content, reason = await anti_injector.process_message(
message_data, self.context.chat_stream
)
# 根据反注入结果处理消息数据
await anti_injector.handle_message_storage(
result, modified_content, reason, message_data
)
await anti_injector.handle_message_storage(result, modified_content, reason, message_data)
if result == ProcessResult.BLOCKED_BAN:
# 用户被封禁 - 直接阻止回复生成
anti_injector_logger.warning(f"用户被反注入系统封禁,阻止回复生成: {reason}")
@@ -236,7 +237,7 @@ class ResponseHandler:
else:
# 没有反击内容时阻止回复生成
return None
# 检查是否需要加盾处理
safety_prompt = None
if result == ProcessResult.SHIELDED:
@@ -245,7 +246,7 @@ class ResponseHandler:
safety_prompt = shield.get_safety_system_prompt()
await Prompt.create_async(safety_prompt, "anti_injection_safety_prompt")
anti_injector_logger.info(f"消息已被反注入系统加盾处理,已注入安全提示词: {reason}")
# 处理被修改的消息内容(用于生成回复)
modified_reply_to = reply_to
if modified_content:
@@ -258,7 +259,7 @@ class ResponseHandler:
else:
# 如果格式不标准,直接使用修改后的内容
modified_reply_to = modified_content
# === 正常的回复生成流程 ===
success, reply_set, _ = await generator_api.generate_reply(
chat_stream=self.context.chat_stream,
@@ -277,4 +278,4 @@ class ResponseHandler:
except Exception as e:
logger.error(f"{self.context.log_prefix}回复生成出现错误:{str(e)} {traceback.format_exc()}")
return None
return None

View File

@@ -8,14 +8,15 @@ from .hfc_context import HfcContext
logger = get_logger("wakeup")
class WakeUpManager:
def __init__(self, context: HfcContext):
"""
初始化唤醒度管理器
Args:
context: HFC聊天上下文对象
功能说明:
- 管理休眠状态下的唤醒度累积
- 处理唤醒度的自然衰减
@@ -29,7 +30,7 @@ class WakeUpManager:
self._decay_task: Optional[asyncio.Task] = None
self.last_log_time = 0
self.log_interval = 30
# 从配置文件获取参数
sleep_config = global_config.sleep_system
self.wakeup_threshold = sleep_config.wakeup_threshold
@@ -40,7 +41,7 @@ class WakeUpManager:
self.angry_duration = sleep_config.angry_duration
self.enabled = sleep_config.enable
self.angry_prompt = sleep_config.angry_prompt
self._load_wakeup_state()
def _get_storage_key(self) -> str:
@@ -73,7 +74,7 @@ class WakeUpManager:
if not self.enabled:
logger.info(f"{self.context.log_prefix} 唤醒度系统已禁用,跳过启动")
return
if not self._decay_task:
self._decay_task = asyncio.create_task(self._decay_loop())
self._decay_task.add_done_callback(self._handle_decay_completion)
@@ -100,18 +101,19 @@ class WakeUpManager:
"""唤醒度衰减循环"""
while self.context.running:
await asyncio.sleep(self.decay_interval)
current_time = time.time()
# 检查愤怒状态是否过期
if self.is_angry and current_time - self.angry_start_time >= self.angry_duration:
self.is_angry = False
# 通知情绪管理系统清除愤怒状态
from src.mood.mood_manager import mood_manager
mood_manager.clear_angry_from_wakeup(self.context.stream_id)
logger.info(f"{self.context.log_prefix} 愤怒状态结束,恢复正常")
self._save_wakeup_state()
# 唤醒度自然衰减
if self.wakeup_value > 0:
old_value = self.wakeup_value
@@ -123,27 +125,28 @@ class WakeUpManager:
def add_wakeup_value(self, is_private_chat: bool, is_mentioned: bool = False) -> bool:
"""
增加唤醒度值
Args:
is_private_chat: 是否为私聊
is_mentioned: 是否被艾特(仅群聊有效)
Returns:
bool: 是否达到唤醒阈值
"""
# 如果系统未启用,直接返回
if not self.enabled:
return False
# 只有在休眠且非失眠状态下才累积唤醒度
from src.schedule.schedule_manager import schedule_manager
from src.schedule.sleep_manager import SleepState
current_sleep_state = schedule_manager.get_current_sleep_state()
if current_sleep_state != SleepState.SLEEPING:
return False
old_value = self.wakeup_value
if is_private_chat:
# 私聊每条消息都增加唤醒度
self.wakeup_value += self.private_message_increment
@@ -155,19 +158,23 @@ class WakeUpManager:
else:
# 群聊未被艾特,不增加唤醒度
return False
current_time = time.time()
if current_time - self.last_log_time > self.log_interval:
logger.info(f"{self.context.log_prefix} 唤醒度变化: {old_value:.1f} -> {self.wakeup_value:.1f} (阈值: {self.wakeup_threshold})")
logger.info(
f"{self.context.log_prefix} 唤醒度变化: {old_value:.1f} -> {self.wakeup_value:.1f} (阈值: {self.wakeup_threshold})"
)
self.last_log_time = current_time
else:
logger.debug(f"{self.context.log_prefix} 唤醒度变化: {old_value:.1f} -> {self.wakeup_value:.1f} (阈值: {self.wakeup_threshold})")
logger.debug(
f"{self.context.log_prefix} 唤醒度变化: {old_value:.1f} -> {self.wakeup_value:.1f} (阈值: {self.wakeup_threshold})"
)
# 检查是否达到唤醒阈值
if self.wakeup_value >= self.wakeup_threshold:
self._trigger_wakeup()
return True
self._save_wakeup_state()
return False
@@ -176,17 +183,19 @@ class WakeUpManager:
self.is_angry = True
self.angry_start_time = time.time()
self.wakeup_value = 0.0 # 重置唤醒度
self._save_wakeup_state()
# 通知情绪管理系统进入愤怒状态
from src.mood.mood_manager import mood_manager
mood_manager.set_angry_from_wakeup(self.context.stream_id)
# 通知日程管理器重置睡眠状态
from src.schedule.schedule_manager import schedule_manager
schedule_manager.reset_sleep_state_after_wakeup()
logger.info(f"{self.context.log_prefix} 唤醒度达到阈值({self.wakeup_threshold}),被吵醒进入愤怒状态!")
def get_angry_prompt_addition(self) -> str:
@@ -203,6 +212,7 @@ class WakeUpManager:
self.is_angry = False
# 通知情绪管理系统清除愤怒状态
from src.mood.mood_manager import mood_manager
mood_manager.clear_angry_from_wakeup(self.context.stream_id)
logger.info(f"{self.context.log_prefix} 愤怒状态自动过期")
return False
@@ -214,5 +224,7 @@ class WakeUpManager:
"wakeup_value": self.wakeup_value,
"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
}
"angry_remaining_time": max(0, self.angry_duration - (time.time() - self.angry_start_time))
if self.is_angry
else 0,
}