From fe201c389e662b17d1df9425c5a8a1f2d61f9921 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Sat, 27 Sep 2025 15:47:30 +0800 Subject: [PATCH] 1 --- src/chat/chat_loop/heartFC_chat.py | 221 +++++++++++++++-------------- 1 file changed, 111 insertions(+), 110 deletions(-) diff --git a/src/chat/chat_loop/heartFC_chat.py b/src/chat/chat_loop/heartFC_chat.py index fca7df847..adc868117 100644 --- a/src/chat/chat_loop/heartFC_chat.py +++ b/src/chat/chat_loop/heartFC_chat.py @@ -39,6 +39,7 @@ class HeartFChatting: """ self.context = HfcContext(chat_id) self.context.new_message_queue = asyncio.Queue() + self._processing_lock = asyncio.Lock() self.cycle_tracker = CycleTracker(self.context) self.response_handler = ResponseHandler(self.context) @@ -357,130 +358,130 @@ class HeartFChatting: - FOCUS模式:直接处理所有消息并检查退出条件 - NORMAL模式:检查进入FOCUS模式的条件,并通过normal_mode_handler处理消息 """ - # --- 核心状态更新 --- - await self.sleep_manager.update_sleep_state(self.wakeup_manager) - current_sleep_state = self.sleep_manager.get_current_sleep_state() - is_sleeping = current_sleep_state == SleepState.SLEEPING - is_in_insomnia = current_sleep_state == SleepState.INSOMNIA + async with self._processing_lock: + # --- 核心状态更新 --- + await self.sleep_manager.update_sleep_state(self.wakeup_manager) + current_sleep_state = self.sleep_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 or is_in_insomnia) + # 核心修复:在睡眠模式(包括失眠)下获取消息时,不过滤命令消息,以确保@消息能被接收 + filter_command_flag = not (is_sleeping or is_in_insomnia) - # 从队列中获取所有待处理的新消息 - recent_messages = [] - while not self.context.new_message_queue.empty(): - recent_messages.append(await self.context.new_message_queue.get()) + # 从队列中获取所有待处理的新消息 + recent_messages = [] + while not self.context.new_message_queue.empty(): + recent_messages.append(await self.context.new_message_queue.get()) - has_new_messages = bool(recent_messages) - new_message_count = len(recent_messages) + has_new_messages = bool(recent_messages) + new_message_count = len(recent_messages) - # 只有在有新消息时才进行思考循环处理 - if has_new_messages: - self.context.last_message_time = time.time() - self.context.last_read_time = time.time() + # 只有在有新消息时才进行思考循环处理 + if has_new_messages: + self.context.last_message_time = time.time() + self.context.last_read_time = time.time() - # --- 专注模式安静群组检查 --- - quiet_groups = global_config.chat.focus_mode_quiet_groups - if quiet_groups and self.context.chat_stream: - is_group_chat = self.context.chat_stream.group_info is not None - if is_group_chat: - try: - platform = self.context.chat_stream.platform - group_id = self.context.chat_stream.group_info.group_id - - # 兼容不同QQ适配器的平台名称 - is_qq_platform = platform in ["qq", "napcat"] - - current_chat_identifier = f"{platform}:{group_id}" - config_identifier_for_qq = f"qq:{group_id}" - - is_in_quiet_list = (current_chat_identifier in quiet_groups or - (is_qq_platform and config_identifier_for_qq in quiet_groups)) - - if is_in_quiet_list: - is_mentioned_in_batch = False - for msg in recent_messages: - if msg.get("is_mentioned"): - is_mentioned_in_batch = True - break + # --- 专注模式安静群组检查 --- + quiet_groups = global_config.chat.focus_mode_quiet_groups + if quiet_groups and self.context.chat_stream: + is_group_chat = self.context.chat_stream.group_info is not None + if is_group_chat: + try: + platform = self.context.chat_stream.platform + group_id = self.context.chat_stream.group_info.group_id - if not is_mentioned_in_batch: - logger.info(f"{self.context.log_prefix} 在专注安静模式下,因未被提及而忽略了消息。") - return True # 消耗消息但不做回复 + # 兼容不同QQ适配器的平台名称 + is_qq_platform = platform in ["qq", "napcat"] + + current_chat_identifier = f"{platform}:{group_id}" + config_identifier_for_qq = f"qq:{group_id}" + + is_in_quiet_list = (current_chat_identifier in quiet_groups or + (is_qq_platform and config_identifier_for_qq in quiet_groups)) + + if is_in_quiet_list: + is_mentioned_in_batch = False + for msg in recent_messages: + if msg.get("is_mentioned"): + is_mentioned_in_batch = True + break + + if not is_mentioned_in_batch: + logger.info(f"{self.context.log_prefix} 在专注安静模式下,因未被提及而忽略了消息。") + return True # 消耗消息但不做回复 + except Exception as e: + logger.error(f"{self.context.log_prefix} 检查专注安静群组时出错: {e}") + + # 处理唤醒度逻辑 + 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 = self.sleep_manager.get_current_sleep_state() + + if current_sleep_state == SleepState.SLEEPING: + # 只有在纯粹的 SLEEPING 状态下才跳过消息处理 + return True + + if current_sleep_state == SleepState.WOKEN_UP: + logger.info(f"{self.context.log_prefix} 从睡眠中被唤醒,将处理积压的消息。") + + # 根据聊天模式处理新消息 + should_process, interest_value = await self._should_process_messages(recent_messages) + if not should_process: + # 消息数量不足或兴趣不够,等待 + await asyncio.sleep(0.5) + return True # Skip rest of the logic for this iteration + + # Messages should be processed + action_type = await self.cycle_processor.observe(interest_value=interest_value) + + # 尝试触发表达学习 + if self.context.expression_learner: + try: + await self.context.expression_learner.trigger_learning_for_chat() except Exception as e: - logger.error(f"{self.context.log_prefix} 检查专注安静群组时出错: {e}") + logger.error(f"{self.context.log_prefix} 表达学习触发失败: {e}") - # 处理唤醒度逻辑 - if current_sleep_state in [SleepState.SLEEPING, SleepState.PREPARING_SLEEP, SleepState.INSOMNIA]: - self._handle_wakeup_messages(recent_messages) + # 管理no_reply计数器 + if action_type != "no_reply": + self.recent_interest_records.clear() + self.context.no_reply_consecutive = 0 + logger.debug(f"{self.context.log_prefix} 执行了{action_type}动作,重置no_reply计数器") + else: # action_type == "no_reply" + self.context.no_reply_consecutive += 1 + self._determine_form_type() - # 再次获取最新状态,因为 handle_wakeup 可能导致状态变为 WOKEN_UP - current_sleep_state = self.sleep_manager.get_current_sleep_state() + # 在一轮动作执行完毕后,增加睡眠压力 + 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() - if current_sleep_state == SleepState.SLEEPING: - # 只有在纯粹的 SLEEPING 状态下才跳过消息处理 - return True - - if current_sleep_state == SleepState.WOKEN_UP: - logger.info(f"{self.context.log_prefix} 从睡眠中被唤醒,将处理积压的消息。") - - # 根据聊天模式处理新消息 - should_process, interest_value = await self._should_process_messages(recent_messages) - if not should_process: - # 消息数量不足或兴趣不够,等待 - await asyncio.sleep(0.5) - return True # Skip rest of the logic for this iteration - - # Messages should be processed - action_type = await self.cycle_processor.observe(interest_value=interest_value) - - # 尝试触发表达学习 - if self.context.expression_learner: - try: - await self.context.expression_learner.trigger_learning_for_chat() - except Exception as e: - logger.error(f"{self.context.log_prefix} 表达学习触发失败: {e}") - - # 管理no_reply计数器 - if action_type != "no_reply": - self.recent_interest_records.clear() - self.context.no_reply_consecutive = 0 - logger.debug(f"{self.context.log_prefix} 执行了{action_type}动作,重置no_reply计数器") - else: # action_type == "no_reply" - self.context.no_reply_consecutive += 1 - self._determine_form_type() - - # 在一轮动作执行完毕后,增加睡眠压力 - 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() - - # 如果成功观察,增加能量值并重置累积兴趣值 - self.context.energy_value += 1 / global_config.chat.focus_value - # 重置累积兴趣值,因为消息已经被成功处理 - self.context.breaking_accumulated_interest = 0.0 - logger.info( - f"{self.context.log_prefix} 能量值增加,当前能量值:{self.context.energy_value:.1f},重置累积兴趣值" - ) - - # 更新上一帧的睡眠状态 - self.context.was_sleeping = is_sleeping - - # --- 重新入睡逻辑 --- - # 如果被吵醒了,并且在一定时间内没有新消息,则尝试重新入睡 - if self.sleep_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: + # 如果成功观察,增加能量值并重置累积兴趣值 + self.context.energy_value += 1 / global_config.chat.focus_value + # 重置累积兴趣值,因为消息已经被成功处理 + self.context.breaking_accumulated_interest = 0.0 logger.info( - f"{self.context.log_prefix} 已被唤醒且超过 {re_sleep_delay / 60} 分钟无新消息,尝试重新入睡。" + f"{self.context.log_prefix} 能量值增加,当前能量值:{self.context.energy_value:.1f},重置累积兴趣值" ) - self.sleep_manager.reset_sleep_state_after_wakeup() - # 保存HFC上下文状态 - self.context.save_context_state() + # 更新上一帧的睡眠状态 + self.context.was_sleeping = is_sleeping - return has_new_messages + # --- 重新入睡逻辑 --- + # 如果被吵醒了,并且在一定时间内没有新消息,则尝试重新入睡 + if self.sleep_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} 分钟无新消息,尝试重新入睡。" + ) + self.sleep_manager.reset_sleep_state_after_wakeup() + + # 保存HFC上下文状态 + self.context.save_context_state() + return has_new_messages def _handle_wakeup_messages(self, messages): """