diff --git a/config/bot_config_template.toml b/config/bot_config_template.toml index fb6f8522..7fe5c0a7 100644 --- a/config/bot_config_template.toml +++ b/config/bot_config_template.toml @@ -6,6 +6,9 @@ nickname = "麦麦" min_text_length = 2 # 与麦麦聊天时麦麦只会回答文本大于等于此数的消息 max_context_size = 15 # 麦麦获得的上下文数量,超出数量后自动丢弃 emoji_chance = 0.2 # 麦麦使用表情包的概率 +ban_words = [ + # "403","张三" + ] [emoji] check_interval = 120 # 检查表情包的时间间隔 @@ -69,3 +72,8 @@ key = "SILICONFLOW_KEY" name = "deepseek-ai/deepseek-vl2" base_url = "SILICONFLOW_BASE_URL" key = "SILICONFLOW_KEY" + +[model.embedding] #嵌入 +name = "BAAI/bge-m3" +base_url = "SILICONFLOW_BASE_URL" +key = "SILICONFLOW_KEY" diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index 6fb9b7d3..d119b4ab 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -94,6 +94,13 @@ class ChatBot: plain_text=event.get_plaintext(), reply_message=event.reply, ) + + # 过滤词 + for word in global_config.ban_words: + if word in message.detailed_plain_text: + print(f"\033[1;32m[{message.group_name}]{message.user_nickname}:\033[0m {message.processed_plain_text}") + print(f"\033[1;32m[过滤词识别]\033[0m 消息中含有{word},filtered") + return current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.time)) diff --git a/src/plugins/chat/config.py b/src/plugins/chat/config.py index 77746364..ffd59315 100644 --- a/src/plugins/chat/config.py +++ b/src/plugins/chat/config.py @@ -31,12 +31,15 @@ class BotConfig: build_memory_interval: int = 60 # 记忆构建间隔(秒) EMOJI_CHECK_INTERVAL: int = 120 # 表情包检查间隔(分钟) EMOJI_REGISTER_INTERVAL: int = 10 # 表情包注册间隔(分钟) + + ban_words = set() # 模型配置 llm_reasoning: Dict[str, str] = field(default_factory=lambda: {}) llm_reasoning_minor: Dict[str, str] = field(default_factory=lambda: {}) llm_normal: Dict[str, str] = field(default_factory=lambda: {}) llm_normal_minor: Dict[str, str] = field(default_factory=lambda: {}) + embedding: Dict[str, str] = field(default_factory=lambda: {}) vlm: Dict[str, str] = field(default_factory=lambda: {}) API_USING: str = "siliconflow" # 使用的API @@ -50,8 +53,8 @@ class BotConfig: # 默认人设 PROMPT_PERSONALITY=[ - "曾经是一个学习地质的女大学生,现在学习心理学和脑科学,你会刷贴吧,你正在浏览qq群", - "是一个女大学生,你有黑色头发,你会刷小红书, 你正在浏览qq群" + "曾经是一个学习地质的女大学生,现在学习心理学和脑科学,你会刷贴吧", + "是一个女大学生,你有黑色头发,你会刷小红书" ] PROMPT_SCHEDULE_GEN="一个曾经学习地质,现在学习心理学和脑科学的女大学生,喜欢刷qq,贴吧,知乎和小红书" @@ -126,7 +129,8 @@ class BotConfig: config.MIN_TEXT_LENGTH = msg_config.get("min_text_length", config.MIN_TEXT_LENGTH) config.MAX_CONTEXT_SIZE = msg_config.get("max_context_size", config.MAX_CONTEXT_SIZE) config.emoji_chance = msg_config.get("emoji_chance", config.emoji_chance) - + config.ban_words=msg_config.get("ban_words",config.ban_words) + if "memory" in toml_dict: memory_config = toml_dict["memory"] config.build_memory_interval = memory_config.get("build_memory_interval", config.build_memory_interval) diff --git a/src/plugins/chat/llm_generator.py b/src/plugins/chat/llm_generator.py index cc60f252..95a936e8 100644 --- a/src/plugins/chat/llm_generator.py +++ b/src/plugins/chat/llm_generator.py @@ -152,4 +152,42 @@ class ResponseGenerator: emotion_tags = await self._get_emotion_tags(content) processed_response = process_llm_response(content) - return processed_response, emotion_tags \ No newline at end of file + return processed_response, emotion_tags + + +class InitiativeMessageGenerate: + def __init__(self): + self.db = Database.get_instance() + self.model_r1 = LLM_request(model=global_config.llm_reasoning, temperature=0.7) + self.model_v3 = LLM_request(model=global_config.llm_normal, temperature=0.7) + self.model_r1_distill = LLM_request( + model=global_config.llm_reasoning_minor, temperature=0.7 + ) + + def gen_response(self, message: Message): + topic_select_prompt, dots_for_select, prompt_template = ( + prompt_builder._build_initiative_prompt_select(message.group_id) + ) + content_select, reasoning = self.model_v3.generate_response(topic_select_prompt) + print(f"[DEBUG] {content_select} {reasoning}") + topics_list = [dot[0] for dot in dots_for_select] + if content_select: + if content_select in topics_list: + select_dot = dots_for_select[topics_list.index(content_select)] + else: + return None + else: + return None + prompt_check, memory = prompt_builder._build_initiative_prompt_check( + select_dot[1], prompt_template + ) + content_check, reasoning_check = self.model_v3.generate_response(prompt_check) + print(f"[DEBUG] {content_check} {reasoning_check}") + if "yes" not in content_check.lower(): + return None + prompt = prompt_builder._build_initiative_prompt( + select_dot, prompt_template, memory + ) + content, reasoning = self.model_r1.generate_response(prompt) + print(f"[DEBUG] {content} {reasoning}") + return content diff --git a/src/plugins/chat/prompt_builder.py b/src/plugins/chat/prompt_builder.py index 2127d97d..707c035a 100644 --- a/src/plugins/chat/prompt_builder.py +++ b/src/plugins/chat/prompt_builder.py @@ -151,12 +151,11 @@ class PromptBuilder: prompt_personality = '' personality_choice = random.random() if personality_choice < 4/6: # 第一种人格 - prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[0]},{promt_info_prompt}, + prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[0]}, 你正在浏览qq群,{promt_info_prompt}, 现在请你给出日常且口语化的回复,平淡一些,尽量简短一些。{is_bot_prompt} 请注意把握群里的聊天内容,不要刻意突出自身学科背景,不要回复的太有条理,可以有个性。''' elif personality_choice < 1: # 第二种人格 - prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[1]},{promt_info_prompt}, - + prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[1]}, 你正在浏览qq群,{promt_info_prompt}, 现在请你给出日常且口语化的回复,请表现你自己的见解,不要一昧迎合,尽量简短一些。{is_bot_prompt} 请你表达自己的见解和观点。可以有个性。''' @@ -196,13 +195,65 @@ class PromptBuilder: prompt_personality_check = '' extra_check_info=f"请注意把握群里的聊天内容的基础上,综合群内的氛围,例如,和{global_config.BOT_NICKNAME}相关的话题要积极回复,如果是at自己的消息一定要回复,如果自己正在和别人聊天一定要回复,其他话题如果合适搭话也可以回复,如果认为应该回复请输出yes,否则输出no,请注意是决定是否需要回复,而不是编写回复内容,除了yes和no不要输出任何回复内容。" if personality_choice < 4/6: # 第一种人格 - prompt_personality_check = f'''你的网名叫{global_config.BOT_NICKNAME},{personality[0]},{promt_info_prompt} {activate_prompt_check} {extra_check_info}''' + prompt_personality_check = f'''你的网名叫{global_config.BOT_NICKNAME},{personality[0]}, 你正在浏览qq群,{promt_info_prompt} {activate_prompt_check} {extra_check_info}''' elif personality_choice < 1: # 第二种人格 - prompt_personality_check = f'''你的网名叫{global_config.BOT_NICKNAME},{personality[1]},{promt_info_prompt} {activate_prompt_check} {extra_check_info}''' + prompt_personality_check = f'''你的网名叫{global_config.BOT_NICKNAME},{personality[1]}, 你正在浏览qq群,{promt_info_prompt} {activate_prompt_check} {extra_check_info}''' prompt_check_if_response=f"{prompt_info}\n{prompt_date}\n{chat_talking_prompt}\n{prompt_personality_check}" return prompt,prompt_check_if_response + + def _build_initiative_prompt_select(self,group_id): + current_date = time.strftime("%Y-%m-%d", time.localtime()) + current_time = time.strftime("%H:%M:%S", time.localtime()) + bot_schedule_now_time,bot_schedule_now_activity = bot_schedule.get_current_task() + prompt_date = f'''今天是{current_date},现在是{current_time},你今天的日程是:\n{bot_schedule.today_schedule}\n你现在正在{bot_schedule_now_activity}\n''' + + chat_talking_prompt = '' + if group_id: + chat_talking_prompt = get_recent_group_detailed_plain_text(self.db, group_id, limit=global_config.MAX_CONTEXT_SIZE,combine = True) + + chat_talking_prompt = f"以下是群里正在聊天的内容:\n{chat_talking_prompt}" + # print(f"\033[1;34m[调试]\033[0m 已从数据库获取群 {group_id} 的消息记录:{chat_talking_prompt}") + + # 获取主动发言的话题 + all_nodes=memory_graph.dots + all_nodes=filter(lambda dot:len(dot[1]['memory_items'])>3,all_nodes) + nodes_for_select=random.sample(all_nodes,5) + topics=[info[0] for info in nodes_for_select] + infos=[info[1] for info in nodes_for_select] + + #激活prompt构建 + activate_prompt = '' + activate_prompt = f"以上是群里正在进行的聊天。" + personality=global_config.PROMPT_PERSONALITY + prompt_personality = '' + personality_choice = random.random() + if personality_choice < 4/6: # 第一种人格 + prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[0]}''' + elif personality_choice < 1: # 第二种人格 + prompt_personality = f'''{activate_prompt}你的网名叫{global_config.BOT_NICKNAME},{personality[1]}''' + + topics_str=','.join(f"\"{topics}\"") + prompt_for_select=f"你现在想在群里发言,回忆了一下,想到几个话题,分别是{topics_str},综合当前状态以及群内气氛,请你在其中选择一个合适的话题,注意只需要输出话题,除了话题什么也不要输出(双引号也不要输出)" + + prompt_initiative_select=f"{prompt_date}\n{prompt_personality}\n{prompt_for_select}" + prompt_regular=f"{prompt_date}\n{prompt_personality}" + + return prompt_initiative_select,nodes_for_select,prompt_regular + + def _build_initiative_prompt_check(self,selected_node,prompt_regular): + memory=random.sample(selected_node['memory_items'],3) + prompt_for_check=f"{prompt_regular}你现在想在群里发言,回忆了一下,想到一个话题,是\"{selected_node['concept']}\",关于这个话题的记忆有\n{'\n'.join(memory)}\n,以这个作为主题发言合适吗?\ + 请在把握群里的聊天内容的基础上,综合群内的氛围,如果认为应该发言请输出yes,否则输出no,请注意是决定是否需要发言,而不是编写回复内容,除了yes和no不要输出任何回复内容。" + return prompt_for_check,memory + + def _build_initiative_prompt(self,selected_node,prompt_regular,memory): + prompt_for_initiative=f"{prompt_regular}你现在想在群里发言,回忆了一下,想到一个话题,是\"{selected_node['concept']}\",关于这个话题的记忆有\n{'\n'.join(memory)}\n,\ + 请在把握群里的聊天内容的基础上,综合群内的氛围,以日常且口语化的口吻,简短且随意一点进行发言,不要说的太有条理,可以有个性。记住不要输出多余内容(包括前后缀,冒号和引号,\ + 括号,表情等)" + return prompt_for_initiative + def get_prompt_info(self,message:str,threshold:float): related_info = '' diff --git a/src/plugins/chat/topic_identifier.py b/src/plugins/chat/topic_identifier.py index f397a876..5c51e0bd 100644 --- a/src/plugins/chat/topic_identifier.py +++ b/src/plugins/chat/topic_identifier.py @@ -107,4 +107,4 @@ class TopicIdentifier: print(f"\033[1;31m[错误]\033[0m SnowNLP 处理失败: {str(e)}") return None -topic_identifier = TopicIdentifier() +topic_identifier = TopicIdentifier() \ No newline at end of file