diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 2ccbe82bd..cbd984e8d 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -100,6 +100,7 @@ class HeartFChatting: # 循环控制内部状态 self.running: bool = False self._loop_task: Optional[asyncio.Task] = None # 主循环任务 + self._energy_task: Optional[asyncio.Task] = None # 添加循环信息管理相关的属性 self.history_loop: List[CycleDetail] = [] @@ -139,6 +140,9 @@ class HeartFChatting: # 标记为活动状态,防止重复启动 self.running = True + self._energy_task = asyncio.create_task(self._energy_loop()) + self._energy_task.add_done_callback(self._handle_energy_completion) + self._loop_task = asyncio.create_task(self._main_chat_loop()) self._loop_task.add_done_callback(self._handle_loop_completion) logger.info(f"{self.log_prefix} HeartFChatting 启动完成") @@ -173,6 +177,22 @@ class HeartFChatting: self.history_loop.append(self._current_cycle_detail) self._current_cycle_detail.timers = cycle_timers self._current_cycle_detail.end_time = time.time() + + + def _handle_energy_completion(self, task: asyncio.Task): + if exception := task.exception(): + logger.error(f"{self.log_prefix} HeartFChatting: 能量循环异常: {exception}") + logger.error(traceback.format_exc()) + else: + logger.info(f"{self.log_prefix} HeartFChatting: 能量循环完成") + + async def _energy_loop(self): + while self.running: + await asyncio.sleep(1) + if self.loop_mode == ChatMode.NORMAL: + self.energy_value -= 1 + if self.energy_value <= 0: + self.energy_value = 0 def print_cycle_info(self, cycle_timers): # 记录循环信息和计时器结果 @@ -190,12 +210,16 @@ class HeartFChatting: async def _loopbody(self): if self.loop_mode == ChatMode.FOCUS: - self.energy_value -= 5 * global_config.chat.focus_value + if await self._observe(): + self.energy_value -= 1 * global_config.chat.focus_value + else: + self.energy_value -= 3 * global_config.chat.focus_value if self.energy_value <= 0: + self.energy_value = 0 self.loop_mode = ChatMode.NORMAL return True - return await self._observe() + return False elif self.loop_mode == ChatMode.NORMAL: new_messages_data = get_raw_msg_by_timestamp_with_chat( chat_id=self.stream_id, @@ -206,17 +230,24 @@ class HeartFChatting: filter_bot=True, ) - if len(new_messages_data) > 4 * global_config.chat.focus_value: + if len(new_messages_data) > 3 * global_config.chat.focus_value: + self.loop_mode = ChatMode.FOCUS + self.energy_value = 10 + (new_messages_data / 3) * 10 + return True + + if self.energy_value >= 30 * global_config.chat.focus_value: self.loop_mode = ChatMode.FOCUS - self.energy_value = 100 return True if new_messages_data: earliest_messages_data = new_messages_data[0] self.last_read_time = earliest_messages_data.get("time") - await self.normal_response(earliest_messages_data) - return True + if_think = await self.normal_response(earliest_messages_data) + if if_think: + self.energy_value *= 1.1 + logger.info(f"{self.log_prefix} 麦麦进行了思考,能量值增加1,当前能量值:{self.energy_value}") + return False await asyncio.sleep(1) @@ -234,6 +265,7 @@ class HeartFChatting: async def _observe(self, message_data: Optional[Dict[str, Any]] = None): if not message_data: message_data = {} + action_type = "no_action" # 创建新的循环信息 cycle_timers, thinking_id = self.start_cycle() @@ -322,6 +354,8 @@ class HeartFChatting: success, reply_text, command = await self._handle_action( action_type, reasoning, action_data, cycle_timers, thinking_id, action_message ) + + loop_info = { "loop_plan_info": { @@ -346,6 +380,9 @@ class HeartFChatting: if self.loop_mode == ChatMode.NORMAL: await self.willing_manager.after_generate_reply_handle(message_data.get("message_id", "")) + if action_type != "no_reply" and action_type != "no_action": + return True + return True async def _main_chat_loop(self): @@ -432,110 +469,6 @@ class HeartFChatting: traceback.print_exc() return False, "", "" - # async def shutdown(self): - # """优雅关闭HeartFChatting实例,取消活动循环任务""" - # logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...") - # self.running = False # <-- 在开始关闭时设置标志位 - - # # 记录最终的消息统计 - # if self._message_count > 0: - # logger.info(f"{self.log_prefix} 本次focus会话共发送了 {self._message_count} 条消息") - # if self._fatigue_triggered: - # logger.info(f"{self.log_prefix} 因疲惫而退出focus模式") - - # # 取消循环任务 - # if self._loop_task and not self._loop_task.done(): - # logger.info(f"{self.log_prefix} 正在取消HeartFChatting循环任务") - # self._loop_task.cancel() - # try: - # await asyncio.wait_for(self._loop_task, timeout=1.0) - # logger.info(f"{self.log_prefix} HeartFChatting循环任务已取消") - # except (asyncio.CancelledError, asyncio.TimeoutError): - # pass - # except Exception as e: - # logger.error(f"{self.log_prefix} 取消循环任务出错: {e}") - # else: - # logger.info(f"{self.log_prefix} 没有活动的HeartFChatting循环任务") - - # # 清理状态 - # self.running = False - # self._loop_task = None - - # # 重置消息计数器,为下次启动做准备 - # self.reset_message_count() - - # logger.info(f"{self.log_prefix} HeartFChatting关闭完成") - - def adjust_reply_frequency(self): - """ - 根据预设规则动态调整回复意愿(willing_amplifier)。 - - 评估周期:10分钟 - - 目标频率:由 global_config.chat.talk_frequency 定义(例如 1条/分钟) - - 调整逻辑: - - 0条回复 -> 5.0x 意愿 - - 达到目标回复数 -> 1.0x 意愿(基准) - - 达到目标2倍回复数 -> 0.2x 意愿 - - 中间值线性变化 - - 增益抑制:如果最近5分钟回复过快,则不增加意愿。 - """ - # --- 1. 定义参数 --- - evaluation_minutes = 10.0 - target_replies_per_min = global_config.chat.get_current_talk_frequency( - self.stream_id - ) # 目标频率:e.g. 1条/分钟 - target_replies_in_window = target_replies_per_min * evaluation_minutes # 10分钟内的目标回复数 - - if target_replies_in_window <= 0: - logger.debug(f"[{self.log_prefix}] 目标回复频率为0或负数,不调整意愿放大器。") - return - - # --- 2. 获取近期统计数据 --- - stats_10_min = get_recent_message_stats(minutes=evaluation_minutes, chat_id=self.stream_id) - bot_reply_count_10_min = stats_10_min["bot_reply_count"] - - # --- 3. 计算新的意愿放大器 (willing_amplifier) --- - # 基于回复数在 [0, target*2] 区间内进行分段线性映射 - if bot_reply_count_10_min <= target_replies_in_window: - # 在 [0, 目标数] 区间,意愿从 5.0 线性下降到 1.0 - new_amplifier = 5.0 + (bot_reply_count_10_min - 0) * (1.0 - 5.0) / (target_replies_in_window - 0) - elif bot_reply_count_10_min <= target_replies_in_window * 2: - # 在 [目标数, 目标数*2] 区间,意愿从 1.0 线性下降到 0.2 - over_target_cap = target_replies_in_window * 2 - new_amplifier = 1.0 + (bot_reply_count_10_min - target_replies_in_window) * (0.2 - 1.0) / ( - over_target_cap - target_replies_in_window - ) - else: - # 超过目标数2倍,直接设为最小值 - new_amplifier = 0.2 - - # --- 4. 检查是否需要抑制增益 --- - # "如果邻近5分钟内,回复数量 > 频率/2,就不再进行增益" - suppress_gain = False - if new_amplifier > self.willing_amplifier: # 仅在计算结果为增益时检查 - suppression_minutes = 5.0 - # 5分钟内目标回复数的一半 - suppression_threshold = (target_replies_per_min / 2) * suppression_minutes # e.g., (1/2)*5 = 2.5 - stats_5_min = get_recent_message_stats(minutes=suppression_minutes, chat_id=self.stream_id) - bot_reply_count_5_min = stats_5_min["bot_reply_count"] - - if bot_reply_count_5_min > suppression_threshold: - suppress_gain = True - - # --- 5. 更新意愿放大器 --- - if suppress_gain: - logger.debug( - f"[{self.log_prefix}] 回复增益被抑制。最近5分钟内回复数 ({bot_reply_count_5_min}) " - f"> 阈值 ({suppression_threshold:.1f})。意愿放大器保持在 {self.willing_amplifier:.2f}" - ) - # 不做任何改动 - else: - # 限制最终值在 [0.2, 5.0] 范围内 - self.willing_amplifier = max(0.2, min(5.0, new_amplifier)) - logger.debug( - f"[{self.log_prefix}] 调整回复意愿。10分钟内回复: {bot_reply_count_10_min} (目标: {target_replies_in_window:.0f}) -> " - f"意愿放大器更新为: {self.willing_amplifier:.2f}" - ) - async def normal_response(self, message_data: dict) -> None: """ 处理接收到的消息。 @@ -575,12 +508,18 @@ class HeartFChatting: f"{message_data.get('user_nickname')}:" f"{message_data.get('processed_plain_text')}[兴趣:{interested_rate:.2f}][回复概率:{reply_probability * 100:.1f}%]" ) + + talk_frequency = global_config.chat.get_current_talk_frequency(self.stream_id) + reply_probability = talk_frequency * reply_probability if random.random() < reply_probability: await self.willing_manager.before_generate_reply_handle(message_data.get("message_id", "")) await self._observe(message_data=message_data) + return True + # 意愿管理器:注销当前message信息 (无论是否回复,只要处理过就删除) + return False self.willing_manager.delete(message_data.get("message_id", "")) async def _generate_response( diff --git a/src/plugins/built_in/core_actions/no_reply.py b/src/plugins/built_in/core_actions/no_reply.py index 2880d1ec2..33cf3dfb0 100644 --- a/src/plugins/built_in/core_actions/no_reply.py +++ b/src/plugins/built_in/core_actions/no_reply.py @@ -88,9 +88,10 @@ class NoReplyAction(BaseAction): new_message_count = len(recent_messages_dict) # 2. 检查消息数量是否达到阈值 - if new_message_count >= exit_message_count_threshold: + talk_frequency = global_config.chat.get_current_talk_frequency(self.stream_id) + if new_message_count >= exit_message_count_threshold / talk_frequency: logger.info( - f"{self.log_prefix} 累计消息数量达到{new_message_count}条(>{exit_message_count_threshold}),结束等待" + f"{self.log_prefix} 累计消息数量达到{new_message_count}条(>{exit_message_count_threshold / talk_frequency}),结束等待" ) exit_reason = f"{global_config.bot.nickname}(你)看到了{new_message_count}条新消息,可以考虑一下是否要进行回复" await self.store_action_info( @@ -108,10 +109,13 @@ class NoReplyAction(BaseAction): interest_value = msg_dict.get("interest_value", 0.0) if text: accumulated_interest += interest_value - logger.info(f"{self.log_prefix} 当前累计兴趣值: {accumulated_interest:.2f}") - if accumulated_interest >= self._interest_exit_threshold: + + talk_frequency = global_config.chat.get_current_talk_frequency(self.stream_id) + logger.info(f"{self.log_prefix} 当前累计兴趣值: {accumulated_interest:.2f}, 当前聊天频率: {talk_frequency:.2f}") + + if accumulated_interest >= self._interest_exit_threshold / talk_frequency: logger.info( - f"{self.log_prefix} 累计兴趣值达到{accumulated_interest:.2f}(>{self._interest_exit_threshold}),结束等待" + f"{self.log_prefix} 累计兴趣值达到{accumulated_interest:.2f}(>{self._interest_exit_threshold / talk_frequency}),结束等待" ) exit_reason = f"{global_config.bot.nickname}(你)感觉到了大家浓厚的兴趣(兴趣值{accumulated_interest:.1f}),决定重新加入讨论" await self.store_action_info(