diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index b90b3d0f3..b8624dae0 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -228,6 +228,7 @@ class ChatBot: config=global_config, is_emoji=message.is_emoji, interested_rate=interested_rate, + sender_id=str(message.message_info.user_info.user_id), ) current_willing = willing_manager.get_willing(chat_stream=chat) @@ -258,6 +259,9 @@ class ChatBot: willing_manager.change_reply_willing_sent(chat) response, raw_content = await self.gpt.generate_response(message) + else: + # 决定不回复时,也更新回复意愿 + willing_manager.change_reply_willing_not_sent(chat) # print(f"response: {response}") if response: diff --git a/src/plugins/chat/willing_manager.py b/src/plugins/chat/willing_manager.py index 773d40c6e..6df27f3a4 100644 --- a/src/plugins/chat/willing_manager.py +++ b/src/plugins/chat/willing_manager.py @@ -1,109 +1,259 @@ import asyncio +import random +import time from typing import Dict +from loguru import logger from .config import global_config from .chat_stream import ChatStream -from loguru import logger - class WillingManager: def __init__(self): self.chat_reply_willing: Dict[str, float] = {} # 存储每个聊天流的回复意愿 + self.chat_high_willing_mode: Dict[str, bool] = {} # 存储每个聊天流是否处于高回复意愿期 + self.chat_msg_count: Dict[str, int] = {} # 存储每个聊天流接收到的消息数量 + self.chat_last_mode_change: Dict[str, float] = {} # 存储每个聊天流上次模式切换的时间 + self.chat_high_willing_duration: Dict[str, int] = {} # 高意愿期持续时间(秒) + self.chat_low_willing_duration: Dict[str, int] = {} # 低意愿期持续时间(秒) + self.chat_last_reply_time: Dict[str, float] = {} # 存储每个聊天流上次回复的时间 + self.chat_last_sender_id: Dict[str, str] = {} # 存储每个聊天流上次回复的用户ID + self.chat_conversation_context: Dict[str, bool] = {} # 标记是否处于对话上下文中 self._decay_task = None + self._mode_switch_task = None self._started = False - + async def _decay_reply_willing(self): """定期衰减回复意愿""" while True: await asyncio.sleep(5) for chat_id in self.chat_reply_willing: - self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6) - + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + if is_high_mode: + # 高回复意愿期内轻微衰减 + self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95) + else: + # 低回复意愿期内正常衰减 + self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8) + + async def _mode_switch_check(self): + """定期检查是否需要切换回复意愿模式""" + while True: + current_time = time.time() + await asyncio.sleep(10) # 每10秒检查一次 + + for chat_id in self.chat_high_willing_mode: + last_change_time = self.chat_last_mode_change.get(chat_id, 0) + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + + # 获取当前模式的持续时间 + duration = 0 + if is_high_mode: + duration = self.chat_high_willing_duration.get(chat_id, 180) # 默认3分钟 + else: + duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200)) # 默认5-20分钟 + + # 检查是否需要切换模式 + if current_time - last_change_time > duration: + self._switch_willing_mode(chat_id) + elif not is_high_mode and random.random() < 0.1: + # 低回复意愿期有10%概率随机切换到高回复期 + self._switch_willing_mode(chat_id) + + # 检查对话上下文状态是否需要重置 + last_reply_time = self.chat_last_reply_time.get(chat_id, 0) + if current_time - last_reply_time > 300: # 5分钟无交互,重置对话上下文 + self.chat_conversation_context[chat_id] = False + + def _switch_willing_mode(self, chat_id: str): + """切换聊天流的回复意愿模式""" + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + + if is_high_mode: + # 从高回复期切换到低回复期 + self.chat_high_willing_mode[chat_id] = False + self.chat_reply_willing[chat_id] = 0.1 # 设置为最低回复意愿 + self.chat_low_willing_duration[chat_id] = random.randint(600, 1200) # 10-20分钟 + logger.debug(f"聊天流 {chat_id} 切换到低回复意愿期,持续 {self.chat_low_willing_duration[chat_id]} 秒") + else: + # 从低回复期切换到高回复期 + self.chat_high_willing_mode[chat_id] = True + self.chat_reply_willing[chat_id] = 1.0 # 设置为较高回复意愿 + self.chat_high_willing_duration[chat_id] = random.randint(180, 240) # 3-4分钟 + logger.debug(f"聊天流 {chat_id} 切换到高回复意愿期,持续 {self.chat_high_willing_duration[chat_id]} 秒") + + self.chat_last_mode_change[chat_id] = time.time() + self.chat_msg_count[chat_id] = 0 # 重置消息计数 + def get_willing(self, chat_stream: ChatStream) -> float: """获取指定聊天流的回复意愿""" stream = chat_stream if stream: return self.chat_reply_willing.get(stream.stream_id, 0) return 0 - + def set_willing(self, chat_id: str, willing: float): """设置指定聊天流的回复意愿""" self.chat_reply_willing[chat_id] = willing - - async def change_reply_willing_received( - self, - chat_stream: ChatStream, - topic: str = None, - is_mentioned_bot: bool = False, - config=None, - is_emoji: bool = False, - interested_rate: float = 0, - ) -> float: + + def _ensure_chat_initialized(self, chat_id: str): + """确保聊天流的所有数据已初始化""" + if chat_id not in self.chat_reply_willing: + self.chat_reply_willing[chat_id] = 0.1 + + if chat_id not in self.chat_high_willing_mode: + self.chat_high_willing_mode[chat_id] = False + self.chat_last_mode_change[chat_id] = time.time() + self.chat_low_willing_duration[chat_id] = random.randint(300, 1200) # 5-20分钟 + + if chat_id not in self.chat_msg_count: + self.chat_msg_count[chat_id] = 0 + + if chat_id not in self.chat_conversation_context: + self.chat_conversation_context[chat_id] = False + + async def change_reply_willing_received(self, + chat_stream: ChatStream, + topic: str = None, + is_mentioned_bot: bool = False, + config = None, + is_emoji: bool = False, + interested_rate: float = 0, + sender_id: str = None) -> float: """改变指定聊天流的回复意愿并返回回复概率""" # 获取或创建聊天流 stream = chat_stream chat_id = stream.stream_id - + current_time = time.time() + + self._ensure_chat_initialized(chat_id) + + # 增加消息计数 + self.chat_msg_count[chat_id] = self.chat_msg_count.get(chat_id, 0) + 1 + current_willing = self.chat_reply_willing.get(chat_id, 0) - - if is_mentioned_bot and current_willing < 1.0: - current_willing += 0.9 + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + msg_count = self.chat_msg_count.get(chat_id, 0) + in_conversation_context = self.chat_conversation_context.get(chat_id, False) + + # 检查是否是对话上下文中的追问 + last_reply_time = self.chat_last_reply_time.get(chat_id, 0) + last_sender = self.chat_last_sender_id.get(chat_id, "") + is_follow_up_question = False + + # 如果是同一个人在短时间内(2分钟内)发送消息,且消息数量较少(<=5条),视为追问 + if sender_id and sender_id == last_sender and current_time - last_reply_time < 120 and msg_count <= 5: + is_follow_up_question = True + in_conversation_context = True + self.chat_conversation_context[chat_id] = True + logger.debug(f"检测到追问 (同一用户), 提高回复意愿") + current_willing += 0.3 + + # 特殊情况处理 + if is_mentioned_bot: + current_willing += 0.5 + in_conversation_context = True + self.chat_conversation_context[chat_id] = True logger.debug(f"被提及, 当前意愿: {current_willing}") - elif is_mentioned_bot: - current_willing += 0.05 - logger.debug(f"被重复提及, 当前意愿: {current_willing}") - + if is_emoji: current_willing *= 0.1 logger.debug(f"表情包, 当前意愿: {current_willing}") - - logger.debug(f"放大系数_interested_rate: {global_config.response_interested_rate_amplifier}") - interested_rate *= global_config.response_interested_rate_amplifier # 放大回复兴趣度 - if interested_rate > 0.4: - # print(f"兴趣度: {interested_rate}, 当前意愿: {current_willing}") - current_willing += interested_rate - 0.4 - - current_willing *= global_config.response_willing_amplifier # 放大回复意愿 - # print(f"放大系数_willing: {global_config.response_willing_amplifier}, 当前意愿: {current_willing}") - - reply_probability = max((current_willing - 0.45) * 2, 0) - + + # 根据话题兴趣度适当调整 + if interested_rate > 0.5: + current_willing += (interested_rate - 0.5) * 0.5 + + # 根据当前模式计算回复概率 + base_probability = 0.0 + + if in_conversation_context: + # 在对话上下文中,降低基础回复概率 + base_probability = 0.5 if is_high_mode else 0.25 + logger.debug(f"处于对话上下文中,基础回复概率: {base_probability}") + elif is_high_mode: + # 高回复周期:4-8句话有50%的概率会回复一次 + base_probability = 0.50 if 4 <= msg_count <= 8 else 0.2 + else: + # 低回复周期:需要最少15句才有30%的概率会回一句 + base_probability = 0.30 if msg_count >= 15 else 0.03 * min(msg_count, 10) + + # 考虑回复意愿的影响 + reply_probability = base_probability * current_willing + # 检查群组权限(如果是群聊) - if chat_stream.group_info: + if chat_stream.group_info and config: if chat_stream.group_info.group_id in config.talk_frequency_down_groups: reply_probability = reply_probability / global_config.down_frequency_rate - reply_probability = min(reply_probability, 1) + # 限制最大回复概率 + reply_probability = min(reply_probability, 0.75) # 设置最大回复概率为75% if reply_probability < 0: reply_probability = 0 - + + # 记录当前发送者ID以便后续追踪 + if sender_id: + self.chat_last_sender_id[chat_id] = sender_id + self.chat_reply_willing[chat_id] = min(current_willing, 3.0) return reply_probability - + def change_reply_willing_sent(self, chat_stream: ChatStream): """开始思考后降低聊天流的回复意愿""" stream = chat_stream if stream: - current_willing = self.chat_reply_willing.get(stream.stream_id, 0) - self.chat_reply_willing[stream.stream_id] = max(0, current_willing - 2) - - def change_reply_willing_after_sent(self, chat_stream: ChatStream): - """发送消息后提高聊天流的回复意愿""" + chat_id = stream.stream_id + self._ensure_chat_initialized(chat_id) + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + current_willing = self.chat_reply_willing.get(chat_id, 0) + + # 回复后减少回复意愿 + self.chat_reply_willing[chat_id] = max(0, current_willing - 0.3) + + # 标记为对话上下文中 + self.chat_conversation_context[chat_id] = True + + # 记录最后回复时间 + self.chat_last_reply_time[chat_id] = time.time() + + # 重置消息计数 + self.chat_msg_count[chat_id] = 0 + + def change_reply_willing_not_sent(self, chat_stream: ChatStream): + """决定不回复后提高聊天流的回复意愿""" stream = chat_stream if stream: - current_willing = self.chat_reply_willing.get(stream.stream_id, 0) - if current_willing < 1: - self.chat_reply_willing[stream.stream_id] = min(1, current_willing + 0.2) - + chat_id = stream.stream_id + self._ensure_chat_initialized(chat_id) + is_high_mode = self.chat_high_willing_mode.get(chat_id, False) + current_willing = self.chat_reply_willing.get(chat_id, 0) + in_conversation_context = self.chat_conversation_context.get(chat_id, False) + + # 根据当前模式调整不回复后的意愿增加 + if is_high_mode: + willing_increase = 0.1 + elif in_conversation_context: + # 在对话上下文中但决定不回复,小幅增加回复意愿 + willing_increase = 0.15 + else: + willing_increase = random.uniform(0.05, 0.1) + + self.chat_reply_willing[chat_id] = min(2.0, current_willing + willing_increase) + + def change_reply_willing_after_sent(self, chat_stream: ChatStream): + """发送消息后提高聊天流的回复意愿""" + # 由于已经在sent中处理,这个方法保留但不再需要额外调整 + pass + async def ensure_started(self): - """确保衰减任务已启动""" + """确保所有任务已启动""" if not self._started: if self._decay_task is None: self._decay_task = asyncio.create_task(self._decay_reply_willing()) + if self._mode_switch_task is None: + self._mode_switch_task = asyncio.create_task(self._mode_switch_check()) self._started = True - # 创建全局实例 -willing_manager = WillingManager() +willing_manager = WillingManager() \ No newline at end of file