From 870be0a4264ac7d5d6e17e132e8f590def838233 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Fri, 28 Feb 2025 00:28:34 +0800 Subject: [PATCH] =?UTF-8?q?v0.2=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E4=B8=9C=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使概率配置生效 将一些模块解耦合 将组信息管理器合并到关系管理器,添加了可以全局调用的接口 精简了llm生成器的代码 精简了message代码 重写了回复后处理 --- README.md | 13 +- src/plugins/chat/bot.py | 79 +++---- src/plugins/chat/bot_config_toml | 5 +- src/plugins/chat/config.py | 9 +- src/plugins/chat/group_info_manager.py | 107 ---------- src/plugins/chat/llm_generator.py | 256 ++++++++--------------- src/plugins/chat/message.py | 81 ++----- src/plugins/chat/message_send_control.py | 203 +++++------------- src/plugins/chat/message_visualizer.py | 2 +- src/plugins/chat/prompt_builder.py | 19 +- src/plugins/chat/relationship_manager.py | 40 +--- src/plugins/chat/utils.py | 156 +++++++++----- src/plugins/chat/utils_user.py | 7 + src/plugins/chat/willing_manager.py | 9 +- 14 files changed, 333 insertions(+), 653 deletions(-) delete mode 100644 src/plugins/chat/group_info_manager.py create mode 100644 src/plugins/chat/utils_user.py diff --git a/README.md b/README.md index c437c12ec..565ae59a3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
![Python Version](https://img.shields.io/badge/Python-3.x-blue) -![License](https://img.shields.io/badge/license-MIT-green) + ![Status](https://img.shields.io/badge/状态-开发中-yellow)
@@ -15,7 +15,8 @@ 基于napcat、nonebot和mongodb的专注于群聊天的qqbot -> ⚠️ **警告**:代码可能随时更改,目前版本不一定是稳定版本,请自行了解qqbot的风险 +> ⚠️ **警告**:代码可能随时更改,目前版本不一定是稳定版本,并请自行了解qqbot的风险 +> ⚠️ **警告**:由于麦麦一直在迭代,所以可能存在一些bug,请自行测试,包括胡言乱语( ## 🚀 快速开始 @@ -44,7 +45,7 @@ ## 🎯 功能介绍 ### 💬 聊天功能 -- 支持关键词检索主动发言:对消息的话题topic进行识别,如果检测到麦麦存储过的话题就会主动进行发言,没写完 +- 支持关键词检索主动发言:对消息的话题topic进行识别,如果检测到麦麦存储过的话题就会主动进行发言,目前有bug - 支持bot名字呼唤发言:检测到"麦麦"会主动发言,可配置 - 使用硅基流动的api进行回复生成,可随机使用R1,V3,R1-distill等模型,未来将加入官网api支持 - 动态的prompt构建器,更拟人 @@ -53,7 +54,7 @@ ### 😊 表情包功能 - 支持根据发言内容发送对应情绪的表情包:未完善,可以用 -- 会自动偷群友的表情包(未完善,暂时禁用) +- 会自动偷群友的表情包(未完善,暂时禁用)目前有bug ### 📅 日程功能 - 麦麦会自动生成一天的日程,实现更拟人的回复 @@ -64,11 +65,9 @@ ### 📚 知识库功能 - 基于embedding模型的知识库,手动放入txt会自动识别,写完了,暂时禁用 -### 📊 可视化的界面 -- 基于gradio的后台界面,可以显示实时消息,思考过程和消息发送流(WIP) - ### 👥 关系功能 - 针对每个用户创建"关系",可以对不同用户进行个性化回复,目前只有极其简单的好感度(WIP) +- 针对每个群创建"群印象",可以对不同群进行个性化回复(WIP) ## 🚧 开发中功能 - 人格功能:WIP diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index 09fc3aa08..489bd14e4 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -6,7 +6,6 @@ from .llm_generator import LLMResponseGenerator from .message_stream import MessageStream, MessageStreamContainer from .topic_identifier import topic_identifier from random import random -from .group_info_manager import GroupInfoManager # 导入群信息管理器 from .emoji_manager import emoji_manager # 导入表情包管理器 import time import os @@ -15,14 +14,13 @@ from .message_send_control import message_sender # 导入消息发送控制器 from .message import Message_Thinking # 导入 Message_Thinking 类 from .relationship_manager import relationship_manager from .willing_manager import willing_manager # 导入意愿管理器 - +from .utils import is_mentioned_bot_in_txt, calculate_typing_time class ChatBot: def __init__(self, config: BotConfig): self.config = config self.storage = MessageStorage() self.gpt = LLMResponseGenerator(config) - self.group_info_manager = GroupInfoManager() # 初始化群信息管理器 self.bot = None # bot 实例引用 self._started = False @@ -79,26 +77,19 @@ class ChatBot: # print(f"- original_message: {event.reply.original_message}") ''' - # 获取群组信息,发送消息的用户信息,并对数据库内容做一次更新 group_info = await bot.get_group_info(group_id=event.group_id) - await self.group_info_manager.update_group_info( - group_id=event.group_id, - group_name=group_info['group_name'], - member_count=group_info['member_count'] - ) + sender_info = await bot.get_group_member_info(group_id=event.group_id, user_id=event.user_id, no_cache=True) - # print(f"\033[1;32m[关系管理]\033[0m 更新关系: {sender_info}") - + 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) print(f"\033[1;32m[关系管理]\033[0m 更新关系值: {relationship_manager.get_relationship(event.user_id).relationship_value}") - message = Message( group_id=event.group_id, user_id=event.user_id, @@ -113,13 +104,12 @@ class ChatBot: topic = topic_identifier.identify_topic_jieba(message.processed_plain_text) print(f"\033[1;32m[主题识别]\033[0m 主题: {topic}") + await self.storage.store_message(message, topic[0] if topic else None) - current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.time)) + - print(f"\033[1;34m[调试]\033[0m 当前消息是否是表情包: {message.is_emoji}") - - is_mentioned = self.is_mentioned_bot(message) + 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, @@ -133,60 +123,47 @@ class ChatBot: print(f"\033[1;32m[{current_time}][{message.group_name}]{message.user_nickname}:\033[0m {message.processed_plain_text}\033[1;36m[回复意愿:{current_willing:.2f}][概率:{reply_probability:.1f}]\033[0m") response = "" + # 创建思考消息 if random() < reply_probability: 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_sender.send_temp_container.add_message(thinking_message) willing_manager.change_reply_willing_sent(thinking_message.group_id) - # 生成回复 + response, emotion = await self.gpt.generate_response(message) # 如果生成了回复,发送并记录 + + if response: message_set = MessageSet(event.group_id, self.config.BOT_QQ, think_id) - if isinstance(response, list): - # 将多条消息合并成一条 - for msg in response: - # print(f"\033[1;34m[调试]\033[0m 载入消息消息: {msg}") - # bot_response_time = round(time.time(), 2) - timepoint = tinking_time_point-0.3 - bot_message = Message( - group_id=event.group_id, - user_id=self.config.BOT_QQ, - message_id=think_id, - message_based_id=event.message_id, - raw_message=msg, - plain_text=msg, - processed_plain_text=msg, - user_nickname="麦麦", - group_name=message.group_name, - time=timepoint - ) - # print(f"\033[1;34m[调试]\033[0m 添加消息到消息组: {bot_message}") - message_set.add_message(bot_message) - # print(f"\033[1;34m[调试]\033[0m 输入消息组: {message_set}") - message_sender.send_temp_container.update_thinking_message(message_set) - else: - # bot_response_time = round(time.time(), 2) + accu_typing_time = 0 + for msg in response: + print(f"当前消息: {msg}") + typing_time = calculate_typing_time(msg) + accu_typing_time += typing_time + timepoint = tinking_time_point+accu_typing_time + # print(f"\033[1;32m[调试]\033[0m 消息: {msg},添加!, 累计打字时间: {accu_typing_time:.2f}秒") + bot_message = Message( group_id=event.group_id, user_id=self.config.BOT_QQ, message_id=think_id, message_based_id=event.message_id, - raw_message=response, - plain_text=response, - processed_plain_text=response, + raw_message=msg, + plain_text=msg, + processed_plain_text=msg, user_nickname="麦麦", group_name=message.group_name, - time=tinking_time_point + time=timepoint ) - # print(f"\033[1;34m[调试]\033[0m 更新单条消息: {bot_message}") - message_sender.send_temp_container.update_thinking_message(bot_message) + message_set.add_message(bot_message) + + message_sender.send_temp_container.update_thinking_message(message_set) + bot_response_time = tinking_time_point @@ -197,8 +174,8 @@ class ChatBot: if random() < 0.5: bot_response_time = tinking_time_point - 1 - # else: - # bot_response_time = bot_response_time + 1 + else: + bot_response_time = bot_response_time + 1 bot_message = Message( group_id=event.group_id, diff --git a/src/plugins/chat/bot_config_toml b/src/plugins/chat/bot_config_toml index 1cef503af..5b9010035 100644 --- a/src/plugins/chat/bot_config_toml +++ b/src/plugins/chat/bot_config_toml @@ -5,6 +5,7 @@ name = "MegBot" [bot] qq = #填入你的机器人QQ +nickname = "麦麦" [message] min_text_length = 2 @@ -16,7 +17,9 @@ check_interval = 120 register_interval = 10 [response] -model_r1_probability = 0.2 #使用R1回复的概率(没启用) +model_r1_probability = 0.8 +model_v3_probability = 0.1 +model_r1_distill_probability = 0.1 [groups] diff --git a/src/plugins/chat/config.py b/src/plugins/chat/config.py index 44e14827d..d44be7bd0 100644 --- a/src/plugins/chat/config.py +++ b/src/plugins/chat/config.py @@ -26,6 +26,7 @@ class BotConfig: DATABASE_NAME: str = "MegBot" BOT_QQ: Optional[int] = None + BOT_NICKNAME: Optional[str] = None # 消息处理相关配置 MIN_TEXT_LENGTH: int = 2 # 最小处理文本长度 @@ -39,7 +40,9 @@ class BotConfig: EMOJI_CHECK_INTERVAL: int = 120 # 表情包检查间隔(分钟) EMOJI_REGISTER_INTERVAL: int = 10 # 表情包注册间隔(分钟) - MODEL_R1_PROBABILITY: float = 0.3 # R1模型概率 + MODEL_R1_PROBABILITY: float = 0.8 # R1模型概率 + MODEL_V3_PROBABILITY: float = 0.1 # V3模型概率 + MODEL_R1_DISTILL_PROBABILITY: float = 0.1 # R1蒸馏模型概率 @classmethod def load_config(cls, config_path: str = "bot_config.toml") -> "BotConfig": @@ -66,11 +69,13 @@ class BotConfig: bot_config = toml_dict["bot"] bot_qq = bot_config.get("qq") config.BOT_QQ = int(bot_qq) - + config.BOT_NICKNAME = bot_config.get("nickname", config.BOT_NICKNAME) if "response" in toml_dict: response_config = toml_dict["response"] config.MODEL_R1_PROBABILITY = response_config.get("model_r1_probability", config.MODEL_R1_PROBABILITY) + config.MODEL_V3_PROBABILITY = response_config.get("model_v3_probability", config.MODEL_V3_PROBABILITY) + config.MODEL_R1_DISTILL_PROBABILITY = response_config.get("model_r1_distill_probability", config.MODEL_R1_DISTILL_PROBABILITY) # 消息配置 if "message" in toml_dict: diff --git a/src/plugins/chat/group_info_manager.py b/src/plugins/chat/group_info_manager.py deleted file mode 100644 index 52cf06138..000000000 --- a/src/plugins/chat/group_info_manager.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import Dict, Optional -from ...common.database import Database -import time - -class GroupInfoManager: - def __init__(self): - self.db = Database.get_instance() - # 确保必要的集合存在 - self._ensure_collections() - - def _ensure_collections(self): - """确保数据库中有必要的集合""" - collections = self.db.db.list_collection_names() - if 'group_info' not in collections: - self.db.db.create_collection('group_info') - if 'user_info' not in collections: - self.db.db.create_collection('user_info') - - async def update_group_info(self, group_id: int, group_name: str, group_notice: str = "", - member_count: int = 0, admins: list = None): - """更新群组信息""" - try: - group_data = { - "group_id": group_id, - "group_name": group_name, - "group_notice": group_notice, - "member_count": member_count, - "admins": admins or [], - "last_updated": time.time() - } - - # 使用 upsert 来更新或插入数据 - self.db.db.group_info.update_one( - {"group_id": group_id}, - {"$set": group_data}, - upsert=True - ) - except Exception as e: - print(f"\033[1;31m[错误]\033[0m 更新群信息失败: {str(e)}") - - async def update_user_info(self, user_id: int, nickname: str, group_id: int = None, - group_card: str = None, age: int = None, gender: str = None, - location: str = None): - """更新用户信息""" - try: - # 基础用户数据 - user_data = { - "user_id": user_id, - "nickname": nickname, - "last_updated": time.time() - } - - # 添加可选字段 - if age is not None: - user_data["age"] = age - if gender is not None: - user_data["gender"] = gender - if location is not None: - user_data["location"] = location - - # 如果提供了群相关信息,更新用户在该群的信息 - if group_id is not None: - group_info_key = f"group_info.{group_id}" - group_data = { - group_info_key: { - "group_card": group_card, - "last_active": time.time() - } - } - user_data.update(group_data) - - # 使用 upsert 来更新或插入数据 - result = self.db.db.user_info.update_one( - {"user_id": user_id}, - { - "$set": user_data, - "$addToSet": {"groups": group_id} if group_id else {} - }, - upsert=True - ) - - # print(f"\033[1;32m[用户信息]\033[0m 更新用户 {nickname}({user_id}) 的信息 {'成功' if result.modified_count > 0 or result.upserted_id else '未变化'}") - - except Exception as e: - print(f"\033[1;31m[错误]\033[0m 更新用户信息失败: {str(e)}") - print(f"用户ID: {user_id}, 昵称: {nickname}, 群ID: {group_id}, 群名片: {group_card}") - - async def get_group_info(self, group_id: int) -> Optional[Dict]: - """获取群组信息""" - try: - return self.db.db.group_info.find_one({"group_id": group_id}) - except Exception as e: - print(f"\033[1;31m[错误]\033[0m 获取群信息失败: {str(e)}") - return None - - async def get_user_info(self, user_id: int, group_id: int = None) -> Optional[Dict]: - """获取用户信息""" - try: - user_info = self.db.db.user_info.find_one({"user_id": user_id}) - if user_info and group_id: - # 添加该用户在特定群的信息 - group_info_key = f"group_info.{group_id}" - user_info["current_group_info"] = user_info.get(group_info_key, {}) - return user_info - except Exception as e: - print(f"\033[1;31m[错误]\033[0m 获取用户信息失败: {str(e)}") - return None \ No newline at end of file diff --git a/src/plugins/chat/llm_generator.py b/src/plugins/chat/llm_generator.py index dece848b2..176996c93 100644 --- a/src/plugins/chat/llm_generator.py +++ b/src/plugins/chat/llm_generator.py @@ -14,8 +14,8 @@ from dotenv import load_dotenv from .relationship_manager import relationship_manager from ..schedule.schedule_generator import bot_schedule from .prompt_builder import prompt_builder -from .config import llm_config -from .utils import get_embedding, split_into_sentences, process_text_with_typos +from .config import llm_config, global_config +from .utils import process_llm_response # 获取当前文件的绝对路径 @@ -38,15 +38,20 @@ class LLMResponseGenerator: async def generate_response(self, message: Message) -> Optional[Union[str, List[str]]]: """根据当前模型类型选择对应的生成函数""" - # 使用随机数选择模型 + # 从global_config中获取模型概率值 + model_r1_probability = global_config.MODEL_R1_PROBABILITY + model_v3_probability = global_config.MODEL_V3_PROBABILITY + model_r1_distill_probability = global_config.MODEL_R1_DISTILL_PROBABILITY + + # 生成随机数并根据概率选择模型 rand = random.random() - if rand < 0.8: # 60%概率使用 R1 - self.current_model_type = "r1" - elif rand < 0.5: # 20%概率使用 V3 - self.current_model_type = "v3" - else: # 20%概率使用 R1-Distill - self.current_model_type = "r1_distill" - + if rand < model_r1_probability: + self.current_model_type = 'r1' + elif rand < model_r1_probability + model_v3_probability: + self.current_model_type = 'v3' + else: + self.current_model_type = 'r1_distill' # 默认使用 R1-Distill + print(f"+++++++++++++++++麦麦{self.current_model_type}思考中+++++++++++++++++") if self.current_model_type == 'r1': model_response = await self._generate_r1_response(message) @@ -64,18 +69,22 @@ class LLMResponseGenerator: return model_response, emotion - async def _generate_r1_response(self, message: Message) -> Optional[str]: - """使用 DeepSeek-R1 模型生成回复""" - # 获取群聊上下文 - group_chat = await self._get_group_chat_context(message) + async def _generate_base_response( + self, + message: Message, + model_name: str, + model_params: Optional[Dict[str, Any]] = None + ) -> Optional[str]: sender_name = message.user_nickname or f"用户{message.user_id}" + + # 获取关系值 if relationship_manager.get_relationship(message.user_id): relationship_value = relationship_manager.get_relationship(message.user_id).relationship_value print(f"\033[1;32m[关系管理]\033[0m 回复中_当前关系值: {relationship_value}") else: relationship_value = 0.0 - - # 构建 prompt + + # 构建prompt prompt = prompt_builder._build_prompt( message_txt=message.processed_plain_text, sender_name=sender_name, @@ -83,142 +92,75 @@ class LLMResponseGenerator: group_id=message.group_id ) + # 设置默认参数 + default_params = { + "model": model_name, + "messages": [{"role": "user", "content": prompt}], + "stream": False, + "max_tokens": 1024, + "temperature": 0.7 + } + + # 更新参数 + if model_params: + default_params.update(model_params) + def create_completion(): - return self.client.chat.completions.create( - model="Pro/deepseek-ai/DeepSeek-R1", - messages=[{"role": "user", "content": prompt}], - stream=False, - max_tokens=1024 - ) - + return self.client.chat.completions.create(**default_params) + loop = asyncio.get_event_loop() response = await loop.run_in_executor(None, create_completion) - if response.choices[0].message.content: - content = response.choices[0].message.content - # 获取推理内容 - reasoning_content = "模型思考过程:\n" + prompt - if hasattr(response.choices[0].message, "reasoning"): - reasoning_content = response.choices[0].message.reasoning or reasoning_content - elif hasattr(response.choices[0].message, "reasoning_content"): - reasoning_content = response.choices[0].message.reasoning_content or reasoning_content - - # 保存推理结果到数据库 - self.db.db.reasoning_logs.insert_one({ - 'time': time.time(), - 'group_id': message.group_id, - 'user': sender_name, - 'message': message.processed_plain_text, - 'model': "DeepSeek-R1", - 'reasoning': reasoning_content, - 'response': content, - 'prompt': prompt - }) - else: + + if not response.choices[0].message.content: return None + + content = response.choices[0].message.content + + # 获取推理内容 + reasoning_content = "模型思考过程:\n" + prompt + if hasattr(response.choices[0].message, "reasoning"): + reasoning_content = response.choices[0].message.reasoning or reasoning_content + elif hasattr(response.choices[0].message, "reasoning_content"): + reasoning_content = response.choices[0].message.reasoning_content or reasoning_content + + # 保存到数据库 + self.db.db.reasoning_logs.insert_one({ + 'time': time.time(), + 'group_id': message.group_id, + 'user': sender_name, + 'message': message.processed_plain_text, + 'model': model_name, + 'reasoning': reasoning_content, + 'response': content, + 'prompt': prompt, + 'model_params': default_params + }) return content + async def _generate_r1_response(self, message: Message) -> Optional[str]: + """使用 DeepSeek-R1 模型生成回复""" + return await self._generate_base_response( + message, + "Pro/deepseek-ai/DeepSeek-R1", + {"temperature": 0.7, "max_tokens": 1024} + ) + async def _generate_v3_response(self, message: Message) -> Optional[str]: """使用 DeepSeek-V3 模型生成回复""" - # 获取群聊上下文 - group_chat = await self._get_group_chat_context(message) - sender_name = message.user_nickname or f"用户{message.user_id}" - - if relationship_manager.get_relationship(message.user_id): - relationship_value = relationship_manager.get_relationship(message.user_id).relationship_value - print(f"\033[1;32m[关系管理]\033[0m 回复中_当前关系值: {relationship_value}") - else: - relationship_value = 0.0 - - prompt = prompt_builder._build_prompt(message.processed_plain_text, sender_name, relationship_value, group_id=message.group_id) - - messages = [{"role": "user", "content": prompt}] - - loop = asyncio.get_event_loop() - create_completion = partial( - self.client.chat.completions.create, - model="Pro/deepseek-ai/DeepSeek-V3", - messages=messages, - stream=False, - max_tokens=1024, - temperature=0.8 + return await self._generate_base_response( + message, + "Pro/deepseek-ai/DeepSeek-V3", + {"temperature": 0.8, "max_tokens": 1024} ) - response = await loop.run_in_executor(None, create_completion) - - if response.choices[0].message.content: - content = response.choices[0].message.content - # 保存推理结果到数据库 - self.db.db.reasoning_logs.insert_one({ - 'time': time.time(), - 'group_id': message.group_id, - 'user': sender_name, - 'message': message.processed_plain_text, - 'model': "DeepSeek-V3", - 'reasoning': "V3模型无推理过程", - 'response': content, - 'prompt': prompt - }) - - return content - else: - print(f"[ERROR] V3 回复发送生成失败: {response}") - - return None async def _generate_r1_distill_response(self, message: Message) -> Optional[str]: """使用 DeepSeek-R1-Distill-Qwen-32B 模型生成回复""" - # 获取群聊上下文 - group_chat = await self._get_group_chat_context(message) - sender_name = message.user_nickname or f"用户{message.user_id}" - if relationship_manager.get_relationship(message.user_id): - relationship_value = relationship_manager.get_relationship(message.user_id).relationship_value - print(f"\033[1;32m[关系管理]\033[0m 回复中_当前关系值: {relationship_value}") - else: - relationship_value = 0.0 - - # 构建 prompt - prompt = prompt_builder._build_prompt( - message_txt=message.processed_plain_text, - sender_name=sender_name, - relationship_value=relationship_value, - group_id=message.group_id + return await self._generate_base_response( + message, + "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", + {"temperature": 0.7, "max_tokens": 1024} ) - - def create_completion(): - return self.client.chat.completions.create( - model="deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - messages=[{"role": "user", "content": prompt}], - stream=False, - max_tokens=1024 - ) - - loop = asyncio.get_event_loop() - response = await loop.run_in_executor(None, create_completion) - if response.choices[0].message.content: - content = response.choices[0].message.content - # 获取推理内容 - reasoning_content = "模型思考过程:\n" + prompt - if hasattr(response.choices[0].message, "reasoning"): - reasoning_content = response.choices[0].message.reasoning or reasoning_content - elif hasattr(response.choices[0].message, "reasoning_content"): - reasoning_content = response.choices[0].message.reasoning_content or reasoning_content - - # 保存推理结果到数据库 - self.db.db.reasoning_logs.insert_one({ - 'time': time.time(), - 'group_id': message.group_id, - 'user': sender_name, - 'message': message.processed_plain_text, - 'model': "DeepSeek-R1-Distill", - 'reasoning': reasoning_content, - 'response': content, - 'prompt': prompt - }) - else: - return None - - - return content async def _get_group_chat_context(self, message: Message) -> str: """获取群聊上下文""" @@ -271,46 +213,14 @@ class LLMResponseGenerator: print(f"获取情感标签时出错: {e}") return ["neutral"] # 发生错误时返回默认值 - async def _process_response(self, content: str) -> Tuple[Union[str, List[str]], List[str]]: + async def _process_response(self, content: str) -> Tuple[List[str], List[str]]: """处理响应内容,返回处理后的内容和情感标签""" if not content: return None, [] - # 检查回复是否过长(超过200个字符) - if len(content) > 200: - print(f"回复过长 ({len(content)} 字符),返回默认回复") - return "麦麦不知道哦", ["angry"] - emotion_tags = await self._get_emotion_tags(content) - - # 添加错别字和处理标点符号 - processed_response = process_text_with_typos(content) - - # 处理长消息 - if len(processed_response) > 5: - sentences = split_into_sentences(processed_response) - print(f"分割后的句子: {sentences}") - messages = [] - current_message = "" - - for sentence in sentences: - if len(current_message) + len(sentence) <= 5: - current_message += ' ' - current_message += sentence - else: - if current_message: - messages.append(current_message.strip()) - current_message = sentence - - if current_message: - messages.append(current_message.strip()) - - # 检查分割后的消息数量是否过多(超过3条) - if len(messages) > 3: - print(f"分割后消息数量过多 ({len(messages)} 条),返回默认回复") - return "麦麦不知道哦", ["angry"] - - return messages, emotion_tags + + processed_response = process_llm_response(content) return processed_response, emotion_tags diff --git a/src/plugins/chat/message.py b/src/plugins/chat/message.py index 0b2479dac..a13a309db 100644 --- a/src/plugins/chat/message.py +++ b/src/plugins/chat/message.py @@ -9,6 +9,7 @@ from PIL import Image from .config import BotConfig, global_config import urllib3 from .cq_code import CQCode +from .utils_user import get_user_nickname Message = ForwardRef('Message') # 添加这行 @@ -44,32 +45,19 @@ class Message: time: float = None is_emoji: bool = False # 是否是表情包 + has_emoji: bool = False # 是否包含表情包 - reply_benefits: float = 0.0 type: str = 'received' # 消息类型,可以是received或者send - - - """消息数据类:思考消息""" - - # 思考状态相关属性 - is_thinking: bool = False - thinking_text: str = "正在思考..." - thingking_start_time: float = None - thinking_time: float = 0 - - received_message = '' - thinking_response = '' - def __post_init__(self): if self.time is None: self.time = int(time.time()) if not self.user_nickname: - self.user_nickname = self.get_user_nickname(self.user_id) + self.user_nickname = get_user_nickname(self.user_id) if not self.group_name: self.group_name = self.get_groupname(self.group_id) @@ -84,28 +72,6 @@ class Message: for seg in self.message_segments ) - # print(f"\033[1;34m[调试]\033[0m pppttt消息: {self.processed_plain_text}") - def get_user_nickname(self, user_id: int) -> str: - """ - 根据user_id获取用户昵称 - 如果数据库中找不到,则返回默认昵称 - """ - if not user_id: - return "未知用户" - - user_id = int(user_id) - if user_id == int(global_config.BOT_QQ): - return "麦麦" - - # 使用数据库单例 - db = Database.get_instance() - # 查找用户,打印查询条件和结果 - query = {'user_id': user_id} - user = db.db.user_info.find_one(query) - if user: - return user.get('nickname') or f"用户{user_id}" - else: - return f"用户{user_id}" def get_groupname(self, group_id: int) -> str: if not group_id: @@ -127,7 +93,7 @@ class Message: 返回的列表中每个元素都是字典,包含: - type: 'text' 或 CQ码类型 - data: 对于text类型是文本内容,对于CQ码是参数字典 - - translated_text: 经过处理(如AI翻译)后的文本 + - translated_text: 经过处理后的文本 """ segments = [] start = 0 @@ -199,12 +165,16 @@ class Message: }) start = cq_end + 1 - - # 检查是否只包含一个表情包CQ码 + + if len(segments) == 1 and segments[0]['type'] == 'image': - # 检查图片的 subtype 是否为 0(表情包) - if segments[0]['data'].get('subtype') == '0': - self.is_emoji = True + self.is_emoji = True + self.has_emoji_emoji = True + else: + for segment in segments: + if segment['type'] == 'image' and segment['data'].get('sub_type') == '1': + self.has_emoji_emoji = True + break return segments @@ -223,11 +193,6 @@ class Message_Thinking: self.thinking_text = "正在思考..." self.time = int(time.time()) self.thinking_time = 0 - - def update_to_message(self, done_message: Message) -> Message: - """更新为完整消息""" - - return done_message def update_thinking_time(self): self.thinking_time = round(time.time(), 2) - self.time @@ -278,21 +243,6 @@ class MessageSet: return self.messages[left] - def get_latest_message(self) -> Optional[Message]: - """获取最新的消息""" - return self.messages[-1] if self.messages else None - - def get_earliest_message(self) -> Optional[Message]: - """获取最早的消息""" - return self.messages[0] if self.messages else None - - def get_all_messages(self) -> List[Message]: - """获取所有消息""" - return self.messages.copy() - - def get_message_count(self) -> int: - """获取消息数量""" - return len(self.messages) def clear_messages(self) -> None: """清空所有消息""" @@ -311,10 +261,7 @@ class MessageSet: def __len__(self) -> int: return len(self.messages) - @property - def processed_plain_text(self) -> str: - """获取所有消息的文本内容""" - return "\n".join(msg.processed_plain_text for msg in self.messages if msg.processed_plain_text) + diff --git a/src/plugins/chat/message_send_control.py b/src/plugins/chat/message_send_control.py index 40f1a9609..afbc3cd62 100644 --- a/src/plugins/chat/message_send_control.py +++ b/src/plugins/chat/message_send_control.py @@ -6,7 +6,7 @@ from .message import Message, Message_Thinking, MessageSet from .cq_code import CQCode from collections import deque import time -from .storage import MessageStorage # 添加这行导入 +from .storage import MessageStorage from .config import global_config from .message_visualizer import message_visualizer @@ -29,18 +29,18 @@ class SendTemp: if message.time >= self.messages[-1].time: self.messages.append(message) return - + # 使用二分查找找到合适的插入位置 messages_list = list(self.messages) left, right = 0, len(messages_list) - + while left < right: mid = (left + right) // 2 if messages_list[mid].time < message.time: left = mid + 1 else: right = mid - + # 重建消息队列,保持时间顺序 new_messages = deque(maxlen=self.max_size) new_messages.extend(messages_list[:left]) @@ -50,11 +50,6 @@ class SendTemp: def get_earliest_message(self) -> Optional[Message]: """获取时间最早的消息""" message = self.messages.popleft() if self.messages else None - # 如果是思考中的消息且思考时间不够,重新加入队列 - # if (isinstance(message, Message_Thinking) and - # time.time() - message.start_time < 2): # 最少思考2秒 - # self.messages.appendleft(message) - # return None return message def clear(self) -> None: @@ -120,16 +115,7 @@ class SendTempContainer: return list(self.temp_queues.keys()) def update_thinking_message(self, message_obj: Union[Message, MessageSet]) -> bool: - """更新思考中的消息 - - Args: - message_obj: 要更新的消息对象,可以是单条消息或消息组 - - Returns: - bool: 更新是否成功 - """ queue = self.get_queue(message_obj.group_id) - # 使用列表解析找到匹配的消息索引 matching_indices = [ i for i, msg in enumerate(queue.messages) @@ -181,149 +167,66 @@ class MessageSendControl: """设置当前bot实例""" self._current_bot = bot + async def process_group_messages(self, group_id: int): + queue = self.send_temp_container.get_queue(group_id) + if queue.has_messages(): + message = queue.peek_next() + # 处理消息的逻辑 + if isinstance(message, Message_Thinking): + message.update_thinking_time() + thinking_time = message.thinking_time + if thinking_time < 60: # 最少思考2秒 + if int(thinking_time) % 10 == 0: + print(f"\033[1;34m[调试]\033[0m 消息正在思考中,已思考{thinking_time:.1f}秒") + return + else: + print(f"\033[1;34m[调试]\033[0m 思考消息超时,移除") + queue.get_earliest_message() # 移除超时的思考消息 + return + elif isinstance(message, Message): + message = queue.get_earliest_message() + if message and message.processed_plain_text: + print(f"- 群组: {group_id} - 内容: {message.processed_plain_text}") + cost_time = round(time.time(), 2) - message.time + if cost_time > 40: + message.processed_plain_text = CQCode.create_reply_cq(message.message_based_id) + message.processed_plain_text + cur_time = time.time() + await self._current_bot.send_group_msg( + group_id=group_id, + message=str(message.processed_plain_text), + auto_escape=False + ) + cost_time = round(time.time(), 2) - cur_time + print(f"\033[1;34m[调试]\033[0m 消息发送时间: {cost_time}秒") + current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.time)) + print(f"\033[1;32m群 {group_id} 消息, 用户 麦麦, 时间: {current_time}:\033[0m {str(message.processed_plain_text)}") + await self.storage.store_message(message, None) + queue.update_send_time() + if queue.has_messages(): + await asyncio.sleep( + random.uniform( + self.message_interval[0], + self.message_interval[1] + ) + ) + async def start_processor(self, bot: Bot): """启动消息处理器""" self._current_bot = bot while self._running: - await asyncio.sleep(1.5) - # 处理所有群组的消息队列 + await asyncio.sleep(1.5) + tasks = [] for group_id in self.send_temp_container.get_all_groups(): - queue = self.send_temp_container.get_queue(group_id) - if queue.has_messages(): - message = queue.peek_next() - # print(f"\033[1;34m[调试]\033[0m 查看最早的消息: {message}") - if message: - if isinstance(message, Message_Thinking): - # 如果是思考中的消息,检查是否需要继续等待 - message.update_thinking_time() - thinking_time = message.thinking_time - if thinking_time < 60: # 最少思考2秒 - if int(thinking_time) % 10 == 0: - print(f"\033[1;34m[调试]\033[0m 消息正在思考中,已思考{thinking_time:.1f}秒") - continue - else: - print(f"\033[1;34m[调试]\033[0m 思考消息超时,移除") - queue.get_earliest_message() # 移除超时的思考消息 - - elif isinstance(message, Message): - message = queue.get_earliest_message() - if message and message.processed_plain_text: - print(f"- 群组: {group_id} - 内容: {message.processed_plain_text}") - - cost_time = round(time.time(), 2) - message.time - # print(f"\033[1;34m[调试]\033[0m 消息发送111111时间: {cost_time}秒") - if cost_time > 40: - message.processed_plain_text = CQCode.create_reply_cq(message.message_based_id) + message.processed_plain_text - - - - cur_time = time.time() - await self._current_bot.send_group_msg( - group_id=group_id, - message=str(message.processed_plain_text), - auto_escape=False - ) - cost_time = round(time.time(), 2) - cur_time - print(f"\033[1;34m[调试]\033[0m 消息发送时间: {cost_time}秒") - - - current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.time)) - print(f"\033[1;32m群 {group_id} 消息, 用户 麦麦, 时间: {current_time}:\033[0m {str(message.processed_plain_text)}") - await self.storage.store_message(message, None) - - queue.update_send_time() - - if queue.has_messages(): - await asyncio.sleep( - random.uniform( - self.message_interval[0], - self.message_interval[1] - ) - ) - message_visualizer.update_content(self.send_temp_container) - - - async def process_group_queue(self, bot: Bot, group_id: int) -> None: - """处理指定群组的消息队列""" - queue = self.send_temp_container.get_queue(group_id) - while queue.has_messages(): - message = queue.get_earliest_message() - if message and message.processed_plain_text: - await self.send_message( - bot=bot, - group_id=group_id, - content=message.processed_plain_text - ) - queue.update_send_time() - - if queue.has_messages(): - await asyncio.sleep( - random.uniform(self.message_interval[0], self.message_interval[1]) - ) - - async def process_all_queues(self, bot: Bot) -> None: - """处理所有群组的消息队列""" - if not self._running or self._paused: - return + tasks.append(self.process_group_messages(group_id)) - for group_id in self.send_temp_container.get_all_groups(): - await self.process_group_queue(bot, group_id) - - async def send_temp_message(self, - bot: Bot, - group_id: int, - message: Union[Message, Message_Thinking], - with_emoji: bool = False, - emoji_path: Optional[str] = None) -> bool: - """ - 发送单个临时消息 - Args: - bot: Bot实例 - group_id: 群组ID - message: Message对象 - with_emoji: 是否带表情 - emoji_path: 表情图片路径 - Returns: - bool: 发送是否成功 - """ - try: - if with_emoji and emoji_path: - return await self.send_with_emoji( - bot=bot, - group_id=group_id, - text_content=message.processed_plain_text, - emoji_path=emoji_path - ) - else: - return await self.send_message( - bot=bot, - group_id=group_id, - content=message.processed_plain_text - ) - except Exception as e: - print(f"\033[1;31m[错误]\033[0m 发送临时消息失败: {str(e)}") - return False + # 并行处理所有群组的消息 + await asyncio.gather(*tasks) + message_visualizer.update_content(self.send_temp_container) def set_typing_speed(self, min_speed: float, max_speed: float): """设置打字速度范围""" self.typing_speed = (min_speed, max_speed) - - def set_message_interval(self, min_interval: float, max_interval: float): - """设置消息间隔范围""" - self.message_interval = (min_interval, max_interval) - - def pause(self): - """暂停消息处理""" - self._paused = True - - def resume(self): - """恢复消息处理""" - self._paused = False - - def stop(self): - """停止消息处理""" - self._running = False # 创建全局实例 message_sender = MessageSendControl() diff --git a/src/plugins/chat/message_visualizer.py b/src/plugins/chat/message_visualizer.py index 2dd3f98e7..0469af8f6 100644 --- a/src/plugins/chat/message_visualizer.py +++ b/src/plugins/chat/message_visualizer.py @@ -92,7 +92,7 @@ class MessageVisualizer: display_text += f"群组: {msg.group_id}\n" display_text += f"用户: {msg.user_nickname}({msg.user_id})\n" display_text += f"内容: {msg.thinking_text}\n" - display_text += f"思考时间: {msg.thinking_time}秒\n" + display_text += f"思考时间: {int(msg.thinking_time)}秒\n" else: display_text += f"类型: 普通消息\n" display_text += f"时间: {msg_time}\n" diff --git a/src/plugins/chat/prompt_builder.py b/src/plugins/chat/prompt_builder.py index c0f3a8aed..a96d93393 100644 --- a/src/plugins/chat/prompt_builder.py +++ b/src/plugins/chat/prompt_builder.py @@ -76,7 +76,7 @@ class PromptBuilder: activate_prompt = '' activate_prompt = f"以上是群里正在进行的聊天,昵称为 '{sender_name}' 的用户说的:{message_txt}。引起了你的注意,你和他{relation_prompt},你想要{relation_prompt_2}。" - # 检测机器人相关词汇 + #检测机器人相关词汇 bot_keywords = ['人机', 'bot', '机器', '入机', 'robot', '机器人'] is_bot = any(keyword in message_txt.lower() for keyword in bot_keywords) if is_bot: @@ -90,17 +90,29 @@ class PromptBuilder: if personality_choice < 4/6: # 第一种人格 prompt_personality = f'''你的网名叫麦麦,是一个学习地质的女大学生,喜欢摄影,你会刷贴吧,你正在浏览qq群,{promt_info_prompt}, {activate_prompt} - 现在请你给出日常且口语化的回复,平淡一些,尽量简短一些,不要输出感叹号。{is_bot_prompt} + 现在请你给出日常且口语化的回复,平淡一些,尽量简短一些。{is_bot_prompt} 请注意把握群里的聊天内容,不要回复的太有条理,可以有个性。''' elif personality_choice < 1: # 第二种人格 prompt_personality = f'''你的网名叫麦麦,是一个女大学生,你有黑色头发,你会刷小红书, 你正在浏览qq群,{promt_info_prompt}, {activate_prompt} - 现在请你给出日常且口语化的回复,请表现你自己的见解,不要一昧迎合,尽量简短一些,不要输出感叹号。{is_bot_prompt} + 现在请你给出日常且口语化的回复,请表现你自己的见解,不要一昧迎合,尽量简短一些。{is_bot_prompt} 请你表达自己的见解和观点。可以有个性。''' + + #中文高手 + prompt_ger = '' + if random.random() < 0.04: + prompt_ger += '你喜欢用倒装句' + if random.random() < 0.02: + prompt_ger += '你喜欢用反问句' + if random.random() < 0.01: + prompt_ger += '你喜欢用文言文' + #额外信息要求 extra_info = '''但是记得回复平淡一些,简短一些,不要过多提及自身的背景, 记住不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只需要输出回复内容就好,不要输出其他任何内容''' + + #合并prompt prompt = "" # prompt += f"{prompt_info}\n" @@ -108,6 +120,7 @@ class PromptBuilder: prompt += f"{chat_talking_prompt}\n" # prompt += f"{activate_prompt}\n" prompt += f"{prompt_personality}\n" + prompt += f"{prompt_ger}\n" prompt += f"{extra_info}\n" return prompt diff --git a/src/plugins/chat/relationship_manager.py b/src/plugins/chat/relationship_manager.py index 15024e374..7ee7db7ae 100644 --- a/src/plugins/chat/relationship_manager.py +++ b/src/plugins/chat/relationship_manager.py @@ -46,8 +46,8 @@ class Relationship: class RelationshipManager: def __init__(self): self.relationships: dict[int, Relationship] = {} # user_id -> Relationship - #保存 qq号,现在使用昵称,别称 - self.id_name_nickname_table: dict[str, str, list] = {} # name -> [nickname, nickname, ...] + # self.id_name_nickname_table: dict[str, list] = {} # name -> [nickname, nickname, ...] + # print("[关系管理] 初始化 id_name_nickname_table") # 调试信息 async def update_relationship(self, user_id: int, data=None, **kwargs): # 检查是否在内存中已存在 @@ -67,6 +67,9 @@ class RelationshipManager: relationship = Relationship(user_id, data=data) if isinstance(data, dict) else Relationship(user_id, **kwargs) self.relationships[user_id] = relationship + # 更新 id_name_nickname_table + # self.id_name_nickname_table[user_id] = [relationship.nickname] # 别称设置为空列表 + # 保存到数据库 await self.storage_relationship(relationship) relationship.saved = True @@ -149,31 +152,12 @@ class RelationshipManager: }}, upsert=True ) - - @staticmethod - async def get_user_nickname(bot: Bot, user_id: int, group_id: int = None) -> Tuple[str, Optional[str]]: - """ - 通过QQ API获取用户昵称 - """ - - # 获取QQ昵称 - stranger_info = await bot.get_stranger_info(user_id=user_id) - qq_nickname = stranger_info['nickname'] - # 如果提供了群号,获取群昵称 - if group_id: - try: - member_info = await bot.get_group_member_info( - group_id=group_id, - user_id=user_id, - no_cache=True - ) - group_nickname = member_info['card'] or None - return qq_nickname, group_nickname - except: - return qq_nickname, None - - return qq_nickname, None + def get_name(self, user_id: int) -> str: + if user_id in self.relationships: + return self.relationships[user_id].nickname + else: + return "[某人]" def print_all_relationships(self): """打印内存中所有的关系记录""" @@ -193,8 +177,4 @@ class RelationshipManager: print("=" * 50) - - - - relationship_manager = RelationshipManager() \ No newline at end of file diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 96e842114..438475a8f 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -5,6 +5,8 @@ from .message import Message import requests import numpy as np from .config import llm_config +import re + def combine_messages(messages: List[Message]) -> str: """将消息列表组合成格式化的字符串 @@ -115,52 +117,85 @@ def get_recent_group_messages(db, group_id: int, limit: int = 12) -> list: message_objects.reverse() return message_objects -def split_into_sentences(text: str) -> List[str]: +def split_into_sentences_w_remove_punctuation(text: str) -> List[str]: """将文本分割成句子,但保持书名号中的内容完整 - Args: text: 要分割的文本字符串 - Returns: List[str]: 分割后的句子列表 """ - delimiters = ['。', '!', ',', ',', '?', '…', '!', '?', '\n'] # 添加换行符作为分隔符 - remove_chars = [',', ','] # 只移除这两种逗号 - sentences = [] - current_sentence = "" - in_book_title = False # 标记是否在书名号内 + len_text = len(text) + if len_text < 5: + if random.random() < 0.01: + return list(text) # 如果文本很短且触发随机条件,直接按字符分割 + else: + return [text] + if len_text < 12: + split_strength = 0.3 + elif len_text < 32: + split_strength = 0.7 + else: + split_strength = 0.9 + #先移除换行符 + # print(f"split_strength: {split_strength}") - for char in text: - current_sentence += char + # print(f"处理前的文本: {text}") + + # 统一将英文逗号转换为中文逗号 + text = text.replace(',', ',') + text = text.replace('\n', ' ') + + # print(f"处理前的文本: {text}") + + text_no_1 = '' + for letter in text: + # print(f"当前字符: {letter}") + if letter in ['!','!','?','?']: + # print(f"当前字符: {letter}, 随机数: {random.random()}") + if random.random() < split_strength: + letter = '' + if letter in ['。','…']: + # print(f"当前字符: {letter}, 随机数: {random.random()}") + if random.random() < 1 - split_strength: + letter = '' + text_no_1 += letter - # 检查书名号 - if char == '《': - in_book_title = True - elif char == '》': - in_book_title = False + # 对每个逗号单独判断是否分割 + sentences = [text_no_1] + new_sentences = [] + for sentence in sentences: + parts = sentence.split(',') + current_sentence = parts[0] + for part in parts[1:]: + if random.random() < split_strength: + new_sentences.append(current_sentence.strip()) + current_sentence = part + else: + current_sentence += ',' + part + # 处理空格分割 + space_parts = current_sentence.split(' ') + current_sentence = space_parts[0] + for part in space_parts[1:]: + if random.random() < split_strength: + new_sentences.append(current_sentence.strip()) + current_sentence = part + else: + current_sentence += ' ' + part + new_sentences.append(current_sentence.strip()) + sentences = [s for s in new_sentences if s] # 移除空字符串 + + # print(f"分割后的句子: {sentences}") + sentences_done = [] + for sentence in sentences: + sentence = sentence.rstrip(',,') + if random.random() < split_strength*0.5: + sentence = sentence.replace(',', '').replace(',', '') + elif random.random() < split_strength: + sentence = sentence.replace(',', ' ').replace(',', ' ') + sentences_done.append(sentence) - # 只有不在书名号内且是分隔符时才分割 - if char in delimiters and not in_book_title: - if current_sentence.strip(): # 确保不是空字符串 - # 只移除逗号 - clean_sentence = current_sentence - if clean_sentence[-1] in remove_chars: - clean_sentence = clean_sentence[:-1] - if clean_sentence.strip(): - sentences.append(clean_sentence.strip()) - current_sentence = "" - - # 处理最后一个句子 - if current_sentence.strip(): - # 如果最后一个字符是逗号,移除它 - if current_sentence[-1] in remove_chars: - current_sentence = current_sentence[:-1] - sentences.append(current_sentence.strip()) - - # 过滤掉空字符串 - sentences = [s for s in sentences if s.strip()] - - return sentences + print(f"处理后的句子: {sentences_done}") + return sentences_done # 常见的错别字映射 TYPO_DICT = { @@ -259,16 +294,7 @@ def random_remove_punctuation(text: str) -> str: return result def add_typos(text: str) -> str: - """随机给文本添加错别字 - - Args: - text: 要处理的文本 - - Returns: - str: 添加错别字后的文本 - """ TYPO_RATE = 0.02 # 控制错别字出现的概率(2%) - result = "" for char in text: if char in TYPO_DICT and random.random() < TYPO_RATE: @@ -279,15 +305,33 @@ def add_typos(text: str) -> str: result += char return result -def process_text_with_typos(text: str) -> str: - """处理文本,添加错别字和处理标点符号 +def process_llm_response(text: str) -> List[str]: + # processed_response = process_text_with_typos(content) + if len(text) > 200: + print(f"回复过长 ({len(text)} 字符),返回默认回复") + return ['懒得说'] + # 处理长消息 + sentences = split_into_sentences_w_remove_punctuation(add_typos(text)) + # 检查分割后的消息数量是否过多(超过3条) + if len(sentences) > 3: + print(f"分割后消息数量过多 ({len(sentences)} 条),返回默认回复") + return ['麦麦不知道哦'] - Args: - text: 要处理的文本 - - Returns: - str: 处理后的文本 + return sentences + +def calculate_typing_time(input_string: str, chinese_time: float = 0.2, english_time: float = 0.1) -> float: """ - if random.random() < 0.9: # 90%概率进行处理 - return random_remove_punctuation(add_typos(text)) - return text + 计算输入字符串所需的时间,中文和英文字符有不同的输入时间 + input_string (str): 输入的字符串 + chinese_time (float): 中文字符的输入时间,默认为0.3秒 + english_time (float): 英文字符的输入时间,默认为0.15秒 + """ + total_time = 0.0 + for char in input_string: + if '\u4e00' <= char <= '\u9fff': # 判断是否为中文字符 + total_time += chinese_time + else: # 其他字符(如英文) + total_time += english_time + return total_time + + diff --git a/src/plugins/chat/utils_user.py b/src/plugins/chat/utils_user.py new file mode 100644 index 000000000..d4f1575d3 --- /dev/null +++ b/src/plugins/chat/utils_user.py @@ -0,0 +1,7 @@ +from .relationship_manager import relationship_manager +from .config import global_config + +def get_user_nickname(user_id: int) -> str: + if user_id == int(global_config.BOT_QQ): + return global_config.BOT_NICKNAME + return relationship_manager.get_name(user_id) \ No newline at end of file diff --git a/src/plugins/chat/willing_manager.py b/src/plugins/chat/willing_manager.py index 357c64656..79d23606f 100644 --- a/src/plugins/chat/willing_manager.py +++ b/src/plugins/chat/willing_manager.py @@ -27,12 +27,12 @@ class WillingManager: current_willing = self.group_reply_willing.get(group_id, 0) if topic and current_willing < 1: - current_willing += 0.4 + current_willing += 0.3 elif topic: current_willing += 0.05 if is_mentioned_bot and current_willing < 1.0: - current_willing += 1 + current_willing += 0.9 elif is_mentioned_bot: current_willing += 0.05 @@ -47,7 +47,7 @@ class WillingManager: reply_probability = 0 if group_id in config.talk_frequency_down_groups: - reply_probability = reply_probability / 2 + reply_probability = reply_probability / 3.5 if is_mentioned_bot and user_id == int(1026294844): reply_probability = 1 @@ -62,9 +62,8 @@ class WillingManager: def change_reply_willing_after_sent(self, group_id: int): """发送消息后提高群组的回复意愿""" current_willing = self.group_reply_willing.get(group_id, 0) - # 如果当前意愿小于1,增加0.3的意愿值 if current_willing < 1: - self.group_reply_willing[group_id] = min(1, current_willing + 0.8) + self.group_reply_willing[group_id] = min(1, current_willing + 0.4) async def ensure_started(self): """确保衰减任务已启动"""