From ebded9204968036e3d6cc143fff8f5507bb55901 Mon Sep 17 00:00:00 2001 From: Pocketfans Date: Wed, 12 Mar 2025 17:21:39 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A9=E5=9B=9E=E5=A4=8D=E6=9B=B4=E6=8B=9F?= =?UTF-8?q?=E4=BA=BA=E5=8C=96=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=AB=98=E4=BD=8E?= =?UTF-8?q?=E6=84=8F=E6=84=BF=E5=91=A8=E6=9C=9F=E3=80=81=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=AE=80=E5=8D=95=E7=9A=84=E8=BF=BD=E9=97=AE=E5=9B=9E=E7=AD=94?= =?UTF-8?q?=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/bot.py | 273 ++++++++------------- src/plugins/chat/willing_manager.py | 364 +++++++++++++++++++++------- 2 files changed, 378 insertions(+), 259 deletions(-) diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index f335a2ba..c510fe4b 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -1,32 +1,26 @@ -import re import time from random import random + from loguru import logger -from nonebot.adapters.onebot.v11 import ( - Bot, - GroupMessageEvent, - MessageEvent, - PrivateMessageEvent, -) +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent from ..memory_system.memory import hippocampus from ..moods.moods import MoodManager # 导入情绪管理器 from .config import global_config +from .cq_code import CQCode # 导入CQCode模块 from .emoji_manager import emoji_manager # 导入表情包管理器 from .llm_generator import ResponseGenerator -from .message import MessageSending, MessageRecv, MessageThinking, MessageSet -from .message_cq import ( - MessageRecvCQ, +from .message import ( + Message, + Message_Sending, + Message_Thinking, # 导入 Message_Thinking 类 + MessageSet, ) -from .chat_stream import chat_manager - from .message_sender import message_manager # 导入新的消息管理器 from .relationship_manager import relationship_manager from .storage import MessageStorage -from .utils import calculate_typing_time, is_mentioned_bot_in_message -from .utils_image import image_path_to_base64 +from .utils import calculate_typing_time, is_mentioned_bot_in_txt from .willing_manager import willing_manager # 导入意愿管理器 -from .message_base import UserInfo, GroupInfo, Seg class ChatBot: @@ -46,257 +40,188 @@ class ChatBot: if not self._started: self._started = True - async def handle_message(self, event: MessageEvent, bot: Bot) -> None: - """处理收到的消息""" + async def handle_message(self, event: GroupMessageEvent, bot: Bot) -> None: + """处理收到的群消息""" + if event.group_id not in global_config.talk_allowed_groups: + return self.bot = bot # 更新 bot 实例 - # 用户屏蔽,不区分私聊/群聊 if event.user_id in global_config.ban_user_id: return - # 处理私聊消息 - if isinstance(event, PrivateMessageEvent): - if not global_config.enable_friend_chat: # 私聊过滤 - return - else: - try: - user_info = UserInfo( - user_id=event.user_id, - user_nickname=(await bot.get_stranger_info(user_id=event.user_id, no_cache=True))["nickname"], - user_cardname=None, - platform="qq", - ) - except Exception as e: - logger.error(f"获取陌生人信息失败: {e}") - return - logger.debug(user_info) + group_info = await bot.get_group_info(group_id=event.group_id) + sender_info = await bot.get_group_member_info(group_id=event.group_id, user_id=event.user_id, no_cache=True) - # group_info = GroupInfo(group_id=0, group_name="私聊", platform="qq") - group_info = None + await relationship_manager.update_relationship(user_id=event.user_id, data=sender_info) + await relationship_manager.update_relationship_value(user_id=event.user_id, relationship_value=0.5) - # 处理群聊消息 - else: - # 白名单设定由nontbot侧完成 - if event.group_id: - if event.group_id not in global_config.talk_allowed_groups: - return - - user_info = UserInfo( - user_id=event.user_id, - user_nickname=event.sender.nickname, - user_cardname=event.sender.card or None, - platform="qq", - ) - - group_info = GroupInfo(group_id=event.group_id, group_name=None, platform="qq") - - # group_info = await bot.get_group_info(group_id=event.group_id) - # sender_info = await bot.get_group_member_info(group_id=event.group_id, user_id=event.user_id, no_cache=True) - - message_cq = MessageRecvCQ( + message = Message( + group_id=event.group_id, + user_id=event.user_id, message_id=event.message_id, - user_info=user_info, + user_cardname=sender_info['card'], raw_message=str(event.original_message), - group_info=group_info, + plain_text=event.get_plaintext(), reply_message=event.reply, - platform="qq", ) - message_json = message_cq.to_dict() + await message.initialize() - # 进入maimbot - message = MessageRecv(message_json) - groupinfo = message.message_info.group_info - userinfo = message.message_info.user_info - messageinfo = message.message_info - - # 消息过滤,涉及到config有待更新 - - chat = await chat_manager.get_or_create_stream( - platform=messageinfo.platform, user_info=userinfo, group_info=groupinfo - ) - message.update_chat_stream(chat) - await relationship_manager.update_relationship( - chat_stream=chat, - ) - await relationship_manager.update_relationship_value(chat_stream=chat, relationship_value=0.5) - - await message.process() # 过滤词 for word in global_config.ban_words: - if word in message.processed_plain_text: + if word in message.detailed_plain_text: logger.info( - f"[{chat.group_info.group_name if chat.group_info.group_id else '私聊'}]{userinfo.user_nickname}:{message.processed_plain_text}" - ) + f"[{message.group_name}]{message.user_nickname}:{message.processed_plain_text}") logger.info(f"[过滤词识别]消息中含有{word},filtered") return - # 正则表达式过滤 - for pattern in global_config.ban_msgs_regex: - if re.search(pattern, message.raw_message): - logger.info( - f"[{chat.group_info.group_name if chat.group_info.group_id else '私聊'}]{message.user_nickname}:{message.raw_message}" - ) - logger.info(f"[正则表达式过滤]消息匹配到{pattern},filtered") - return - - current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(messageinfo.time)) + current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.time)) # topic=await topic_identifier.identify_topic_llm(message.processed_plain_text) - - topic = "" + topic = '' + interested_rate = 0 interested_rate = await hippocampus.memory_activate_value(message.processed_plain_text) / 100 - logger.debug(f"对{message.processed_plain_text}的激活度:{interested_rate}") + logger.debug(f"对{message.processed_plain_text}" + f"的激活度:{interested_rate}") # logger.info(f"\033[1;32m[主题识别]\033[0m 使用{global_config.topic_extract}主题: {topic}") - await self.storage.store_message(message, chat, topic[0] if topic else None) + await self.storage.store_message(message, topic[0] if topic else None) - is_mentioned = is_mentioned_bot_in_message(message) - reply_probability = await willing_manager.change_reply_willing_received( - chat_stream=chat, - topic=topic[0] if topic else None, - is_mentioned_bot=is_mentioned, - config=global_config, - is_emoji=message.is_emoji, - interested_rate=interested_rate, + is_mentioned = is_mentioned_bot_in_txt(message.processed_plain_text) + reply_probability = willing_manager.change_reply_willing_received( + event.group_id, + topic[0] if topic else None, + is_mentioned, + global_config, + event.user_id, + message.is_emoji, + interested_rate ) - current_willing = willing_manager.get_willing(chat_stream=chat) + current_willing = willing_manager.get_willing(event.group_id) logger.info( - f"[{current_time}][{chat.group_info.group_name if chat.group_info.group_id else '私聊'}]{chat.user_info.user_nickname}:" - f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]" - ) + f"[{current_time}][{message.group_name}]{message.user_nickname}:" + f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]") - response = None + response = "" if random() < reply_probability: - bot_user_info = UserInfo( - user_id=global_config.BOT_QQ, - user_nickname=global_config.BOT_NICKNAME, - platform=messageinfo.platform, - ) - thinking_time_point = round(time.time(), 2) - think_id = "mt" + str(thinking_time_point) - thinking_message = MessageThinking( - message_id=think_id, - chat_stream=chat, - bot_user_info=bot_user_info, - reply=message, - ) + tinking_time_point = round(time.time(), 2) + think_id = 'mt' + str(tinking_time_point) + thinking_message = Message_Thinking(message=message, message_id=think_id) message_manager.add_message(thinking_message) - willing_manager.change_reply_willing_sent(chat) + willing_manager.change_reply_willing_sent(thinking_message.group_id) response, raw_content = await self.gpt.generate_response(message) - # print(f"response: {response}") if response: - # print(f"有response: {response}") - container = message_manager.get_container(chat.stream_id) + container = message_manager.get_container(event.group_id) thinking_message = None # 找到message,删除 - # print(f"开始找思考消息") for msg in container.messages: - if isinstance(msg, MessageThinking) and msg.message_info.message_id == think_id: - # print(f"找到思考消息: {msg}") + if isinstance(msg, Message_Thinking) and msg.message_id == think_id: thinking_message = msg container.messages.remove(msg) + # print(f"\033[1;32m[思考消息删除]\033[0m 已找到思考消息对象,开始删除") break # 如果找不到思考消息,直接返回 if not thinking_message: - logger.warning("未找到对应的思考消息,可能已超时被移除") + logger.warning(f"未找到对应的思考消息,可能已超时被移除") return # 记录开始思考的时间,避免从思考到回复的时间太久 thinking_start_time = thinking_message.thinking_start_time - message_set = MessageSet(chat, think_id) + message_set = MessageSet(event.group_id, global_config.BOT_QQ, + think_id) # 发送消息的id和产生发送消息的message_thinking是一致的 # 计算打字时间,1是为了模拟打字,2是避免多条回复乱序 accu_typing_time = 0 + # print(f"\033[1;32m[开始回复]\033[0m 开始将回复1载入发送容器") mark_head = False for msg in response: # print(f"\033[1;32m[回复内容]\033[0m {msg}") # 通过时间改变时间戳 typing_time = calculate_typing_time(msg) - logger.debug(f"typing_time: {typing_time}") accu_typing_time += typing_time - timepoint = thinking_time_point + accu_typing_time - message_segment = Seg(type="text", data=msg) - # logger.debug(f"message_segment: {message_segment}") - bot_message = MessageSending( + timepoint = tinking_time_point + accu_typing_time + + bot_message = Message_Sending( + group_id=event.group_id, + user_id=global_config.BOT_QQ, message_id=think_id, - chat_stream=chat, - bot_user_info=bot_user_info, - sender_info=userinfo, - message_segment=message_segment, - reply=message, - is_head=not mark_head, - is_emoji=False, + raw_message=msg, + plain_text=msg, + processed_plain_text=msg, + user_nickname=global_config.BOT_NICKNAME, + group_name=message.group_name, + time=timepoint, # 记录了回复生成的时间 + thinking_start_time=thinking_start_time, # 记录了思考开始的时间 + reply_message_id=message.message_id ) - print(f"bot_message: {bot_message}") + await bot_message.initialize() if not mark_head: + bot_message.is_head = True mark_head = True - print(f"添加消息到message_set: {bot_message}") message_set.add_message(bot_message) # message_set 可以直接加入 message_manager # print(f"\033[1;32m[回复]\033[0m 将回复载入发送容器") - - logger.debug("添加message_set到message_manager") - message_manager.add_message(message_set) - bot_response_time = thinking_time_point + bot_response_time = tinking_time_point if random() < global_config.emoji_chance: emoji_raw = await emoji_manager.get_emoji_for_text(response) # 检查是否 <没有找到> emoji if emoji_raw != None: - emoji_path, description = emoji_raw + emoji_path, discription = emoji_raw - emoji_cq = image_path_to_base64(emoji_path) + emoji_cq = CQCode.create_emoji_cq(emoji_path) if random() < 0.5: - bot_response_time = thinking_time_point - 1 + bot_response_time = tinking_time_point - 1 else: bot_response_time = bot_response_time + 1 - message_segment = Seg(type="emoji", data=emoji_cq) - bot_message = MessageSending( - message_id=think_id, - chat_stream=chat, - bot_user_info=bot_user_info, - sender_info=userinfo, - message_segment=message_segment, - reply=message, - is_head=False, + bot_message = Message_Sending( + group_id=event.group_id, + user_id=global_config.BOT_QQ, + message_id=0, + raw_message=emoji_cq, + plain_text=emoji_cq, + processed_plain_text=emoji_cq, + detailed_plain_text=discription, + user_nickname=global_config.BOT_NICKNAME, + group_name=message.group_name, + time=bot_response_time, is_emoji=True, + translate_cq=False, + thinking_start_time=thinking_start_time, + # reply_message_id=message.message_id ) + await bot_message.initialize() message_manager.add_message(bot_message) - emotion = await self.gpt._get_emotion_tags(raw_content) logger.debug(f"为 '{response}' 获取到的情感标签为:{emotion}") valuedict = { - "happy": 0.5, - "angry": -1, - "sad": -0.5, - "surprised": 0.2, - "disgusted": -1.5, - "fearful": -0.7, - "neutral": 0.1, + 'happy': 0.5, + 'angry': -1, + 'sad': -0.5, + 'surprised': 0.2, + 'disgusted': -1.5, + 'fearful': -0.7, + 'neutral': 0.1 } - await relationship_manager.update_relationship_value( - chat_stream=chat, relationship_value=valuedict[emotion[0]] - ) + await relationship_manager.update_relationship_value(message.user_id, + relationship_value=valuedict[emotion[0]]) # 使用情绪管理器更新情绪 self.mood_manager.update_mood_from_emotion(emotion[0], global_config.mood_intensity_factor) - # willing_manager.change_reply_willing_after_sent( - # chat_stream=chat - # ) + # willing_manager.change_reply_willing_after_sent(event.group_id) # 创建全局ChatBot实例 diff --git a/src/plugins/chat/willing_manager.py b/src/plugins/chat/willing_manager.py index f34afb74..64fb8ab1 100644 --- a/src/plugins/chat/willing_manager.py +++ b/src/plugins/chat/willing_manager.py @@ -1,105 +1,298 @@ import asyncio -from typing import Dict - - +import random +import time +from loguru import logger from .config import global_config -from .chat_stream import ChatStream class WillingManager: def __init__(self): - self.chat_reply_willing: Dict[str, float] = {} # 存储每个聊天流的回复意愿 - self.chat_reply_willing: Dict[str, float] = {} # 存储每个聊天流的回复意愿 + self.group_reply_willing = {} # 存储每个群的回复意愿 + self.group_high_willing_until = {} # 存储每个群高回复意愿的截止时间 + self.group_next_high_willing_time = {} # 存储每个群下一次高回复意愿的开始时间 + self.group_message_counter = {} # 存储每个群的消息计数 self._decay_task = None self._started = False + self.min_reply_willing = 0.02 + self.max_reply_willing = 3.0 + self.attenuation_coefficient = 0.9 - 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) - for chat_id in self.chat_reply_willing: - self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6) - - 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 - def set_willing(self, chat_id: str, willing: float): - """设置指定聊天流的回复意愿""" - self.chat_reply_willing[chat_id] = willing + # 高频率回复周期配置 + self.high_willing_min_minutes = 3 # 高回复意愿持续时间最短3分钟 + self.high_willing_max_minutes = 4 # 高回复意愿持续时间最长4分钟 - 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: - """改变指定聊天流的回复意愿并返回回复概率""" - # 获取或创建聊天流 - stream = chat_stream - chat_id = stream.stream_id + # 低频率回复周期配置 + self.cycle_min_minutes = 10 # 两次高回复意愿之间的时间间隔最短10分钟 + self.cycle_max_minutes = 30 # 两次高回复意愿之间的时间间隔最长30分钟 - current_willing = self.chat_reply_willing.get(chat_id, 0) + # 回复意愿变化配置 + self.high_willing_increase = 0.1 # 高回复期内未回复时的意愿增加 + self.low_willing_increase = 0.01 # 低回复期内未回复时的意愿增加 + self.reply_willing_decrease = 0.35 # 回复后的意愿降低 + self.mentioned_willing_increase = 0.2 # 被@时的意愿增加 + self.mentioned_msg_count = 6 # 被@时的消息计数增加值 - # print(f"初始意愿: {current_willing}") - if is_mentioned_bot and current_willing < 1.0: - current_willing += 0.9 - print(f"被提及, 当前意愿: {current_willing}") - elif is_mentioned_bot: - current_willing += 0.05 - print(f"被重复提及, 当前意愿: {current_willing}") + # 消息计数器相关配置 + self.high_period_msg_threshold = 4 # 高回复期内,至少累积几条消息才考虑回复 + self.low_period_msg_threshold = 12 # 低回复期内,至少累积几条消息才考虑回复 - if is_emoji: - current_willing *= 0.1 - print(f"表情包, 当前意愿: {current_willing}") + # 高回复意愿期的回复意愿基础值 + self.high_willing_base = 1.0 - print(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 + # 回复概率上限 + self.high_period_max_probability = 0.65 # 高回复期内最大回复概率 + self.low_period_max_probability = 0.5 # 低回复期内最大回复概率 + self.mentioned_max_probability = 0.5 # 被@时的最大回复概率 - 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 chat_stream.group_info: - if chat_stream.group_info.group_id in config.talk_frequency_down_groups: - reply_probability = reply_probability / global_config.down_frequency_rate + # 低频群组配置 + self.low_freq_high_period_min_probability = 0.15 # 低频群组在高回复期的最低回复概率 + self.low_freq_msg_threshold_reduction = 2 # 低频群组在高回复期的消息阈值降低值 - reply_probability = min(reply_probability, 1) - if reply_probability < 0: - reply_probability = 0 + def _generate_high_willing_period(self) -> int: + """生成高回复意愿的随机持续时间(秒)""" + minutes = random.uniform(self.high_willing_min_minutes, self.high_willing_max_minutes) + return int(minutes * 60) + + def _generate_next_cycle_time(self) -> int: + """生成下一个高回复意愿周期的等待时间(秒)""" + minutes = random.uniform(self.cycle_min_minutes, self.cycle_max_minutes) + return int(minutes * 60) + + async def _decay_reply_willing(self): + """定期衰减回复意愿并管理周期""" + while True: + await asyncio.sleep(5) # 每5秒检查一次 + current_time = time.time() - self.chat_reply_willing[chat_id] = min(current_willing, 3.0) + for group_id in list(self.group_reply_willing.keys()): + # 检查是否处于高回复意愿期 + if group_id in self.group_high_willing_until: + # 如果当前时间超过高回复意愿期,大幅度降低回复意愿 + if current_time > self.group_high_willing_until[group_id]: + self.group_reply_willing[group_id] = self.min_reply_willing + # 移除过期的时间记录 + self.group_high_willing_until.pop(group_id) + # 重置消息计数器 + self.group_message_counter[group_id] = 0 + + # 设置下一次高回复意愿期的开始时间 + next_cycle_time = self._generate_next_cycle_time() + self.group_next_high_willing_time[group_id] = current_time + next_cycle_time + logger.debug(f"群组 {group_id} 高回复意愿期结束,回复意愿重置为 {self.min_reply_willing}," + f"将在 {next_cycle_time/60:.1f} 分钟后进入下一个高回复意愿期") + else: + # 在高回复意愿期内,轻微衰减 + self.group_reply_willing[group_id] = max( + 0.5, # 高回复意愿期的最低值 + self.group_reply_willing[group_id] * 0.95 # 轻微衰减 + ) + # 检查是否需要进入高回复意愿期 + elif group_id in self.group_next_high_willing_time: + if current_time > self.group_next_high_willing_time[group_id]: + # 是时候进入新的高回复意愿期了 + high_period = self._generate_high_willing_period() + self.group_high_willing_until[group_id] = current_time + high_period + self.group_reply_willing[group_id] = self.high_willing_base + # 重置消息计数器 + self.group_message_counter[group_id] = 0 + # 移除下次高意愿时间记录 + self.group_next_high_willing_time.pop(group_id) + logger.debug(f"群组 {group_id} 进入新的高回复意愿期,持续 {high_period/60:.1f} 分钟") + else: + # 正常衰减 + self.group_reply_willing[group_id] = max( + self.min_reply_willing, + self.group_reply_willing[group_id] * self.attenuation_coefficient + ) + else: + # 正常衰减 + self.group_reply_willing[group_id] = max( + self.min_reply_willing, + self.group_reply_willing[group_id] * self.attenuation_coefficient + ) + + # 初始化下一次高回复意愿期 + if group_id not in self.group_next_high_willing_time: + next_cycle_time = self._generate_next_cycle_time() + self.group_next_high_willing_time[group_id] = current_time + next_cycle_time + logger.debug(f"群组 {group_id} 将在 {next_cycle_time/60:.1f} 分钟后进入高回复意愿期") + + def get_willing(self, group_id: int) -> float: + """获取指定群组的回复意愿""" + return self.group_reply_willing.get(group_id, 0) + + def set_willing(self, group_id: int, willing: float): + """设置指定群组的回复意愿""" + self.group_reply_willing[group_id] = willing + + # 如果设置了较高的意愿值,可能需要立即进入高回复意愿期 + if willing > 1.0 and group_id not in self.group_high_willing_until: + high_period = self._generate_high_willing_period() + self.group_high_willing_until[group_id] = time.time() + high_period + # 重置消息计数器 + self.group_message_counter[group_id] = 0 + # 清除下次高意愿时间安排 + if group_id in self.group_next_high_willing_time: + self.group_next_high_willing_time.pop(group_id) + logger.debug(f"群组 {group_id} 立即进入高回复意愿期,持续 {high_period/60:.1f} 分钟") + + def change_reply_willing_received(self, group_id: int, topic: str, is_mentioned_bot: bool, config, + user_id: int = None, is_emoji: bool = False, interested_rate: float = 0) -> float: + + # 若非目标回复群组,则直接return + if group_id not in config.talk_allowed_groups: + reply_probability = 0 + return reply_probability + + # 初始化消息计数器(如果不存在) + if group_id not in self.group_message_counter: + self.group_message_counter[group_id] = 0 + + # 增加消息计数 + self.group_message_counter[group_id] += 1 + + # 初始化群组意愿值(如果不存在) + if group_id not in self.group_reply_willing: + self.group_reply_willing[group_id] = self.min_reply_willing + # 为新群组初始化下一次高回复意愿期 + next_cycle_time = self._generate_next_cycle_time() + self.group_next_high_willing_time[group_id] = time.time() + next_cycle_time + logger.debug(f"新群组 {group_id} 将在 {next_cycle_time/60:.1f} 分钟后进入高回复意愿期") + else: + # 根据当前处于高/低回复期来决定意愿增加量 + current_willing = self.group_reply_willing.get(group_id, 0) + + # 判断是否在高回复意愿期 + in_high_period = group_id in self.group_high_willing_until and time.time() < self.group_high_willing_until[group_id] + + # 根据不同周期选择不同的意愿增加量 + willing_increase = self.high_willing_increase if in_high_period else self.low_willing_increase + + self.group_reply_willing[group_id] = min( + self.max_reply_willing, + current_willing + willing_increase + ) + + period_type = "高" if in_high_period else "低" + logger.debug(f"[{group_id}]处于{period_type}回复期,增加意愿: +{willing_increase},当前: {self.group_reply_willing[group_id]}") + + current_willing = self.group_reply_willing.get(group_id, 0) + logger.debug(f"[{group_id}]的初始回复意愿: {current_willing}") + + # 根据消息类型(被cue/表情包)调控 + if is_mentioned_bot: + # 被@时增加一定意愿值,但不会太高 + current_willing = min( + self.max_reply_willing, + current_willing + self.mentioned_willing_increase + ) + # 被提及时增加一定消息计数,但不会直接确保回复 + self.group_message_counter[group_id] = min( + self.group_message_counter[group_id] + self.mentioned_msg_count, + self.low_period_msg_threshold # 最多增加到低周期阈值 + ) + logger.debug(f"被提及, 当前意愿: {current_willing}, 消息计数增加到: {self.group_message_counter[group_id]}") + + if is_emoji: + current_willing *= 0.5 + logger.debug(f"表情包, 当前意愿: {current_willing}") + + # 兴趣放大系数,若兴趣 > 0.4则增加回复概率 + interested_rate_amplifier = global_config.response_interested_rate_amplifier + logger.debug(f"放大系数_interested_rate: {interested_rate_amplifier}") + interested_rate *= interested_rate_amplifier + + current_willing += max( + 0.0, + interested_rate - 0.4 + ) + + # 回复意愿系数调控,独立乘区 + willing_amplifier = max( + global_config.response_willing_amplifier, + self.min_reply_willing + ) + current_willing *= willing_amplifier + logger.debug(f"放大系数_willing: {global_config.response_willing_amplifier}, 当前意愿: {current_willing}") + + # 回复概率迭代,保底0.01回复概率 + reply_probability = max( + (current_willing - 0.5) * 2.5, + self.min_reply_willing + ) + + # 检查是否在高回复意愿期内 + if group_id in self.group_high_willing_until and time.time() < self.group_high_willing_until[group_id]: + # 在高回复意愿期内 + is_low_freq_group = group_id in config.talk_frequency_down_groups + + # 低频群组在高回复期使用较低的消息阈值 + actual_threshold = self.high_period_msg_threshold + if is_low_freq_group: + actual_threshold = max(2, self.high_period_msg_threshold - self.low_freq_msg_threshold_reduction) + + # 检查消息数量是否达到阈值 + if self.group_message_counter[group_id] >= actual_threshold: + # 提高回复概率,但有上限 + base_probability = reply_probability * 1.2 + + if is_low_freq_group: + # 低频群组在高回复期保持一定的回复概率 + reply_probability = max( + min(base_probability, self.high_period_max_probability * 0.6), # 最高概率降低到正常的60% + self.low_freq_high_period_min_probability # 保证最低概率 + ) + logger.debug(f"低频群组在高回复意愿期内,消息数:{self.group_message_counter[group_id]},设置回复概率为: {reply_probability}") + else: + # 普通群组正常处理 + reply_probability = min(base_probability, self.high_period_max_probability) + logger.debug(f"群组在高回复意愿期内,消息数:{self.group_message_counter[group_id]},提高回复概率至: {reply_probability}") + else: + # 消息数量不足,但在高回复期仍保持一定概率 + if is_low_freq_group: + # 低频群组在高回复期即使消息不足也保持最低概率 + reply_probability = max(reply_probability * 0.5, self.low_freq_high_period_min_probability) + logger.debug(f"低频群组在高回复意愿期内,消息数不足({self.group_message_counter[group_id]}/{actual_threshold}),保持最低概率: {reply_probability}") + else: + # 普通群组正常降低概率 + reply_probability *= 0.5 + logger.debug(f"群组在高回复意愿期内,但消息数不足({self.group_message_counter[group_id]}/{actual_threshold}),降低回复概率至: {reply_probability}") + else: + # 在低回复意愿期内,需要大量消息累积才可能回复 + if self.group_message_counter[group_id] >= self.low_period_msg_threshold: + # 达到了阈值,但概率仍然很低 + reply_probability = min(reply_probability * 0.8, self.low_period_max_probability) + logger.debug(f"群组在低回复意愿期内,消息数达标({self.group_message_counter[group_id]}/{self.low_period_msg_threshold}),回复概率设为: {reply_probability}") + else: + # 消息数不足,几乎不回复 + reply_probability *= 0.05 + logger.debug(f"群组在低回复意愿期内,消息数不足({self.group_message_counter[group_id]}/{self.low_period_msg_threshold}),回复概率极低: {reply_probability}") + + # 如果是被@,限制最终概率不超过mentioned_max_probability + if is_mentioned_bot: + reply_probability = min(reply_probability, self.mentioned_max_probability) + logger.debug(f"被@消息,限制最终回复概率为: {reply_probability}") + + # 最终回复概率限制 + reply_probability = min(reply_probability, 1) + + self.group_reply_willing[group_id] = min(current_willing, self.max_reply_willing) + logger.debug(f"当前群组{group_id}回复概率:{reply_probability}") 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): - """发送消息后提高聊天流的回复意愿""" - 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) - + + def change_reply_willing_sent(self, group_id: int): + """开始思考后降低群组的回复意愿""" + current_willing = self.group_reply_willing.get(group_id, 0) + self.group_reply_willing[group_id] = max(0, current_willing - self.reply_willing_decrease) + # 回复后重置消息计数器 + self.group_message_counter[group_id] = 0 + logger.debug(f"[{group_id}]回复后,降低意愿: -{self.reply_willing_decrease},当前: {self.group_reply_willing[group_id]},消息计数重置为0") + + def change_reply_willing_after_sent(self, group_id: int): + """发送消息后修改群组的回复意愿""" + # 保持降低的意愿,不再额外增加 + pass + async def ensure_started(self): """确保衰减任务已启动""" if not self._started: @@ -107,5 +300,6 @@ class WillingManager: self._decay_task = asyncio.create_task(self._decay_reply_willing()) self._started = True + # 创建全局实例 -willing_manager = WillingManager() \ No newline at end of file +willing_manager = WillingManager()