diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index 794e3ac22..685fb0ea9 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -83,7 +83,7 @@ class ChatBot: chat_stream=chat, ) await relationship_manager.update_relationship_value( - chat_stream=chat, relationship_value=0.5 + chat_stream=chat, relationship_value=0 ) await message.process() @@ -255,20 +255,11 @@ class ChatBot: ) 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, - } - await relationship_manager.update_relationship_value( - chat_stream=chat, relationship_value=valuedict[emotion[0]] - ) + # 获取立场和情感标签,更新关系值 + stance, emotion = await self.gpt._get_emotion_tags(raw_content, message.processed_plain_text) + logger.debug(f"为 '{response}' 立场为:{stance} 获取到的情感标签为:{emotion}") + await relationship_manager.calculate_update_relationship_value(chat_stream=chat, label=emotion, stance=stance) + # 使用情绪管理器更新情绪 self.mood_manager.update_mood_from_emotion( emotion[0], global_config.mood_intensity_factor diff --git a/src/plugins/chat/llm_generator.py b/src/plugins/chat/llm_generator.py index 5fb400b10..192399134 100644 --- a/src/plugins/chat/llm_generator.py +++ b/src/plugins/chat/llm_generator.py @@ -63,25 +63,19 @@ class ResponseGenerator: async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request) -> Optional[str]: """使用指定的模型生成回复""" - sender_name = message.chat_stream.user_info.user_nickname or f"用户{message.chat_stream.user_info.user_id}" - if message.chat_stream.user_info.user_cardname: + sender_name = "" + if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname: sender_name = f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]{message.chat_stream.user_info.user_cardname}" - - # 获取关系值 - relationship_value = ( - relationship_manager.get_relationship(message.chat_stream).relationship_value - if relationship_manager.get_relationship(message.chat_stream) - else 0.0 - ) - if relationship_value != 0.0: - # print(f"\033[1;32m[关系管理]\033[0m 回复中_当前关系值: {relationship_value}") - pass + elif message.chat_stream.user_info.user_nickname: + sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}" + else: + sender_name = f"用户({message.chat_stream.user_info.user_id})" # 构建prompt prompt, prompt_check = await prompt_builder._build_prompt( + message.chat_stream, message_txt=message.processed_plain_text, sender_name=sender_name, - relationship_value=relationship_value, stream_id=message.chat_stream.stream_id, ) @@ -151,32 +145,48 @@ class ResponseGenerator: } ) - async def _get_emotion_tags(self, content: str) -> List[str]: - """提取情感标签""" + async def _get_emotion_tags( + self, content: str, processed_plain_text: str + ): + """提取情感标签,结合立场和情绪""" try: - prompt = f"""请从以下内容中,从"happy,angry,sad,surprised,disgusted,fearful,neutral"中选出最匹配的1个情感标签并输出 - 只输出标签就好,不要输出其他内容: - 内容:{content} - 输出: + # 构建提示词,结合回复内容、被回复的内容以及立场分析 + prompt = f""" + 请根据以下对话内容,完成以下任务: + 1. 判断回复者的立场是"supportive"(支持)、"opposed"(反对)还是"neutrality"(中立)。 + 2. 从"happy,angry,sad,surprised,disgusted,fearful,neutral"中选出最匹配的1个情感标签。 + 3. 按照"立场-情绪"的格式输出结果,例如:"supportive-happy"。 + + 被回复的内容: + {processed_plain_text} + + 回复内容: + {content} + + 请分析回复者的立场和情感倾向,并输出结果: """ - content, _ = await self.model_v25.generate_response(prompt) - content = content.strip() - if content in [ - "happy", - "angry", - "sad", - "surprised", - "disgusted", - "fearful", - "neutral", - ]: - return [content] + + # 调用模型生成结果 + result, _ = await self.model_v25.generate_response(prompt) + result = result.strip() + + # 解析模型输出的结果 + if "-" in result: + stance, emotion = result.split("-", 1) + valid_stances = ["supportive", "opposed", "neutrality"] + valid_emotions = [ + "happy", "angry", "sad", "surprised", "disgusted", "fearful", "neutral" + ] + if stance in valid_stances and emotion in valid_emotions: + return stance, emotion # 返回有效的立场-情绪组合 + else: + return "neutrality", "neutral" # 默认返回中立-中性 else: - return ["neutral"] + return "neutrality", "neutral" # 格式错误时返回默认值 except Exception as e: print(f"获取情感标签时出错: {e}") - return ["neutral"] + return "neutrality", "neutral" # 出错时返回默认值 async def _process_response(self, content: str) -> Tuple[List[str], List[str]]: """处理响应内容,返回处理后的内容和情感标签""" diff --git a/src/plugins/chat/prompt_builder.py b/src/plugins/chat/prompt_builder.py index 8a7bf9c6b..fe9badb52 100644 --- a/src/plugins/chat/prompt_builder.py +++ b/src/plugins/chat/prompt_builder.py @@ -7,8 +7,9 @@ from ..memory_system.memory import hippocampus, memory_graph from ..moods.moods import MoodManager from ..schedule.schedule_generator import bot_schedule from .config import global_config -from .utils import get_embedding, get_recent_group_detailed_plain_text +from .utils import get_embedding, get_recent_group_detailed_plain_text, get_recent_group_speaker from .chat_stream import chat_manager +from .relationship_manager import relationship_manager from src.common.logger import get_module_logger logger = get_module_logger("prompt") @@ -21,34 +22,36 @@ class PromptBuilder: self.prompt_built = "" self.activate_messages = "" - async def _build_prompt( - self, - message_txt: str, - sender_name: str = "某人", - relationship_value: float = 0.0, - stream_id: Optional[int] = None, - ) -> tuple[str, str]: + async def _build_prompt(self, + chat_stream, + message_txt: str, + sender_name: str = "某人", + stream_id: Optional[int] = None) -> tuple[str, str]: """构建prompt Args: message_txt: 消息文本 sender_name: 发送者昵称 - relationship_value: 关系值 + # relationship_value: 关系值 group_id: 群组ID Returns: str: 构建好的prompt """ - # 先禁用关系 - if 0 > 30: - relation_prompt = "关系特别特别好,你很喜欢喜欢他" - relation_prompt_2 = "热情发言或者回复" - elif 0 < -20: - relation_prompt = "关系很差,你很讨厌他" - relation_prompt_2 = "骂他" - else: - relation_prompt = "关系一般" - relation_prompt_2 = "发言或者回复" + # 关系(载入当前聊天记录里部分人的关系) + who_chat_in_group = [chat_stream] + who_chat_in_group += get_recent_group_speaker( + stream_id, + (chat_stream.user_info.user_id, chat_stream.user_info.platform), + limit=global_config.MAX_CONTEXT_SIZE + ) + relation_prompt = "" + for person in who_chat_in_group: + relation_prompt += relationship_manager.build_relationship_info(person) + + relation_prompt_all = ( + f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录,根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。" + ) # 开始构建prompt @@ -70,10 +73,10 @@ class PromptBuilder: ) chat_stream = chat_manager.get_stream(stream_id) if chat_stream.group_info: - chat_talking_prompt = f"以下是群里正在聊天的内容:\n{chat_talking_prompt}" + chat_talking_prompt = chat_talking_prompt else: chat_in_group = False - chat_talking_prompt = f"以下是你正在和{sender_name}私聊的内容:\n{chat_talking_prompt}" + chat_talking_prompt = chat_talking_prompt # print(f"\033[1;34m[调试]\033[0m 已从数据库获取群 {group_id} 的消息记录:{chat_talking_prompt}") # 使用新的记忆获取方法 @@ -123,10 +126,7 @@ class PromptBuilder: probability_3 = global_config.PERSONALITY_3 personality_choice = random.random() - if chat_in_group: - prompt_in_group = f"你正在浏览{chat_stream.platform}群" - else: - prompt_in_group = f"你正在{chat_stream.platform}上和{sender_name}私聊" + if personality_choice < probability_1: # 第一种人格 prompt_personality = personality[0] elif personality_choice < probability_1 + probability_2: # 第二种人格 @@ -143,15 +143,6 @@ class PromptBuilder: if random.random() < 0.01: prompt_ger += "你喜欢用文言文" - # 合并prompt - # prompt = "" - # prompt += f"{prompt_info}\n" - # prompt += f"{prompt_date}\n" - # prompt += f"{chat_talking_prompt}\n" - # prompt += f"{prompt_personality}\n" - # prompt += f"{prompt_ger}\n" - # prompt += f"{extra_info}\n" - # 知识构建 start_time = time.time() @@ -176,7 +167,7 @@ class PromptBuilder: `` {message_txt} ``\ -引起了你的注意,你和ta{relation_prompt},{mood_prompt},你想要{relation_prompt_2}。 +引起了你的注意,{relation_prompt_all}{mood_prompt} `` 你的网名叫{global_config.BOT_NICKNAME},你还有很多别名:{"/".join(global_config.BOT_ALIAS_NAMES)},{prompt_personality}。 @@ -198,8 +189,8 @@ class PromptBuilder: # prompt_personality_check = f"""你的网名叫{global_config.BOT_NICKNAME},{personality[2]}, 你正在浏览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}" + prompt_check_if_response = "" - return prompt, prompt_check_if_response def _build_initiative_prompt_select(self, group_id, probability_1=0.8, probability_2=0.1): diff --git a/src/plugins/chat/relationship_manager.py b/src/plugins/chat/relationship_manager.py index 937f5d7ce..39e4bce1b 100644 --- a/src/plugins/chat/relationship_manager.py +++ b/src/plugins/chat/relationship_manager.py @@ -5,6 +5,7 @@ from src.common.logger import get_module_logger from ...common.database import db from .message_base import UserInfo from .chat_stream import ChatStream +import math logger = get_module_logger("rel_manager") @@ -250,6 +251,101 @@ class RelationshipManager: return user_info.user_nickname or user_info.user_cardname or "某人" else: return "某人" + + async def calculate_update_relationship_value(self, + chat_stream: ChatStream, + label: str, + stance: str) -> None: + """计算变更关系值 + 新的关系值变更计算方式: + 将关系值限定在-1000到1000 + 对于关系值的变更,期望: + 1.向两端逼近时会逐渐减缓 + 2.关系越差,改善越难,关系越好,恶化越容易 + 3.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢 + """ + stancedict = { + "supportive": 0, + "neutrality": 1, + "opposed": 2, + } + + valuedict = { + "happy": 1.5, + "angry": -3.0, + "sad": -1.5, + "surprised": 0.6, + "disgusted": -4.5, + "fearful": -2.1, + "neutral": 0.3, + } + if self.get_relationship(chat_stream): + old_value = self.get_relationship(chat_stream).relationship_value + else: + return + + if old_value > 1000: + old_value = 1000 + elif old_value < -1000: + old_value = -1000 + + value = valuedict[label] + if old_value >= 0: + if valuedict[label] >= 0 and stancedict[stance] != 2: + value = value*math.cos(math.pi*old_value/2000) + if old_value > 500: + high_value_count = 0 + for key, relationship in self.relationships.items(): + if relationship.relationship_value >= 850: + high_value_count += 1 + value *= 3/(high_value_count + 3) + elif valuedict[label] < 0 and stancedict[stance] != 0: + value = value*math.exp(old_value/1000) + else: + value = 0 + elif old_value < 0: + if valuedict[label] >= 0 and stancedict[stance] != 2: + value = value*math.exp(old_value/1000) + elif valuedict[label] < 0 and stancedict[stance] != 0: + value = value*math.cos(math.pi*old_value/2000) + else: + value = 0 + + logger.info(f"[关系变更] 立场:{stance} 标签:{label} 关系值:{value}") + + await self.update_relationship_value( + chat_stream=chat_stream, relationship_value=value + ) + + def build_relationship_info(self,person) -> str: + relationship_value = relationship_manager.get_relationship(person).relationship_value + if -1000 <= relationship_value < -227: + level_num = 0 + elif -227 <= relationship_value < -73: + level_num = 1 + elif -76 <= relationship_value < 227: + level_num = 2 + elif 227 <= relationship_value < 587: + level_num = 3 + elif 587 <= relationship_value < 900: + level_num = 4 + elif 900 <= relationship_value <= 1000: + level_num = 5 + else: + level_num = 5 if relationship_value > 1000 else 0 + + relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] + relation_prompt2_list = [ + "冷漠回应或直接辱骂", "冷淡回复", + "保持理性", "愿意回复", + "积极回复", "无条件支持", + ] + if person.user_info.user_cardname: + return (f"你对昵称为'[({person.user_info.user_id}){person.user_info.user_nickname}]{person.user_info.user_cardname}'的用户的态度为{relationship_level[level_num]}," + f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}。") + else: + return (f"你对昵称为'({person.user_info.user_id}){person.user_info.user_nickname}'的用户的态度为{relationship_level[level_num]}," + f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}。") relationship_manager = RelationshipManager() diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 29f10fc20..ad8d41a68 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -197,6 +197,35 @@ def get_recent_group_detailed_plain_text(chat_stream_id: int, limit: int = 12, c return message_detailed_plain_text_list +def get_recent_group_speaker(chat_stream_id: int, sender, limit: int = 12) -> list: + # 获取当前群聊记录内发言的人 + recent_messages = list(db.messages.find( + {"chat_id": chat_stream_id}, + { + "chat_info": 1, + "user_info": 1, + } + ).sort("time", -1).limit(limit)) + + if not recent_messages: + return [] + + who_chat_in_group = [] # ChatStream列表 + + duplicate_removal = [] + for msg_db_data in recent_messages: + user_info = UserInfo.from_dict(msg_db_data["user_info"]) + if (user_info.user_id, user_info.platform) != sender \ + and (user_info.user_id, user_info.platform) != (global_config.BOT_QQ, "qq") \ + and (user_info.user_id, user_info.platform) not in duplicate_removal \ + and len(duplicate_removal) < 5: # 排除重复,排除消息发送者,排除bot(此处bot的平台强制为了qq,可能需要更改),限制加载的关系数目 + + duplicate_removal.append((user_info.user_id, user_info.platform)) + chat_info = msg_db_data.get("chat_info", {}) + who_chat_in_group.append(ChatStream.from_dict(chat_info)) + return who_chat_in_group + + def split_into_sentences_w_remove_punctuation(text: str) -> List[str]: """将文本分割成句子,但保持书名号中的内容完整 Args: