From 7d4e6870178df20ceb0165097c9afb1634198b0f Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 00:11:16 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E4=BF=A1=E6=81=AF=E7=9A=84person=5Finfo?= =?UTF-8?q?=EF=BC=8C=E5=B0=86=E5=85=B3=E7=B3=BB=E5=80=BC=E5=B9=B6=E5=85=A5?= =?UTF-8?q?=E5=85=B6=E4=B8=AD=EF=BC=8C=E9=80=9A=E8=BF=87person=5Finfo?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E7=AE=A1=E7=90=86=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 7 +- src/plugins/chat/bot.py | 21 +-- src/plugins/chat/llm_generator.py | 5 +- src/plugins/chat/person_info.py | 214 ++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 src/plugins/chat/person_info.py diff --git a/src/main.py b/src/main.py index f58fc0d9d..72e982ffc 100644 --- a/src/main.py +++ b/src/main.py @@ -4,7 +4,7 @@ from .plugins.utils.statistic import LLMStatistics from .plugins.moods.moods import MoodManager from .plugins.schedule.schedule_generator import bot_schedule from .plugins.chat.emoji_manager import emoji_manager -from .plugins.chat.relationship_manager import relationship_manager +from .plugins.chat.person_info import person_info_manager from .plugins.willing.willing_manager import willing_manager from .plugins.chat.chat_stream import chat_manager from .heart_flow.heartflow import heartflow @@ -55,9 +55,8 @@ class MainSystem: self.mood_manager.start_mood_update(update_interval=global_config.mood_update_interval) logger.success("情绪管理器启动成功") - # 加载用户关系 - await relationship_manager.load_all_relationships() - asyncio.create_task(relationship_manager._start_relationship_manager()) + # 检查并清除person_info冗余字段 + await person_info_manager.del_all_undefined_field() # 启动愿望管理器 await willing_manager.ensure_started() diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index ac6d4d2c9..9e01f8e3e 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -158,6 +158,10 @@ class ChatBot: else: mes_name = "私聊" + if message.message_info.additional_config: + if "maimcore_reply_probability_gain" in message.message_info.additional_config.keys(): + reply_probability += message.message_info.additional_config["maimcore_reply_probability_gain"] + # 打印收到的信息的信息 current_time = time.strftime("%H:%M:%S", time.localtime(messageinfo.time)) logger.info( @@ -166,10 +170,6 @@ class ChatBot: f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]" ) - if message.message_info.additional_config: - if "maimcore_reply_probability_gain" in message.message_info.additional_config.keys(): - reply_probability += message.message_info.additional_config["maimcore_reply_probability_gain"] - do_reply = False # 开始组织语言 if random() < reply_probability: @@ -191,7 +191,7 @@ class ChatBot: timing_results["思考前脑内状态"] = timer2 - timer1 timer1 = time.time() - response_set = await self.gpt.generate_response(message) + response_set, undivided_response = await self.gpt.generate_response(message) timer2 = time.time() timing_results["生成回复"] = timer2 - timer1 @@ -223,6 +223,9 @@ class ChatBot: response_msg = " ".join(response_set) if response_set else "无回复" logger.info(f"触发消息: {trigger_msg[:20]}... | 生成消息: {response_msg[:20]}... | 性能计时: {timing_str}") + # 更新情绪和关系 + await self._update_emotion_and_relationship(message, chat, undivided_response) + async def _update_using_response(self, message, response_set): # 更新心流状态 stream_id = message.chat_stream.stream_id @@ -310,17 +313,15 @@ class ChatBot: ) message_manager.add_message(bot_message) - async def _update_emotion_and_relationship(self, message, chat, response, raw_content): + async def _update_emotion_and_relationship(self, message, chat, undivided_response): """更新情绪和关系 Args: message: 接收到的消息 chat: 聊天流对象 - response: 生成的回复 - raw_content: 原始内容 + undivided_response: 生成的未分割回复 """ - stance, emotion = await self.gpt._get_emotion_tags(raw_content, message.processed_plain_text) - logger.debug(f"为 '{response}' 立场为:{stance} 获取到的情感标签为:{emotion}") + stance, emotion = await self.gpt._get_emotion_tags(undivided_response, message.processed_plain_text) await relationship_manager.calculate_update_relationship_value(chat_stream=chat, label=emotion, stance=stance) self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor) diff --git a/src/plugins/chat/llm_generator.py b/src/plugins/chat/llm_generator.py index b0c9a59e2..44681bee3 100644 --- a/src/plugins/chat/llm_generator.py +++ b/src/plugins/chat/llm_generator.py @@ -59,6 +59,7 @@ class ResponseGenerator: current_model = self.model_normal model_response = await self._generate_response_with_model(message, current_model) + undivided_response = model_response # print(f"raw_content: {model_response}") @@ -66,10 +67,10 @@ class ResponseGenerator: logger.info(f"{global_config.BOT_NICKNAME}的回复是:{model_response}") model_response = await self._process_response(model_response) - return model_response + return model_response, undivided_response else: logger.info(f"{self.current_model_type}思考,失败") - return None + return None, None async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request): sender_name = "" diff --git a/src/plugins/chat/person_info.py b/src/plugins/chat/person_info.py new file mode 100644 index 000000000..28e515971 --- /dev/null +++ b/src/plugins/chat/person_info.py @@ -0,0 +1,214 @@ +from src.common.logger import get_module_logger +from ...common.database import db +import copy +import hashlib +from typing import Any, Callable, Dict, TypeVar +T = TypeVar('T') # 泛型类型 + +""" +PersonInfoManager 类方法功能摘要: +1. get_person_id - 根据平台和用户ID生成MD5哈希的唯一person_id +2. create_person_info - 创建新个人信息文档(自动合并默认值) +3. update_one_field - 更新单个字段值(若文档不存在则创建) +4. del_one_document - 删除指定person_id的文档 +5. get_value - 获取单个字段值(返回实际值或默认值) +6. get_values - 批量获取字段值(任一字段无效则返回空字典) +7. del_all_undefined_field - 清理全集合中未定义的字段 +8. get_specific_value_list - 根据指定条件,返回person_id,value字典 +""" + +logger = get_module_logger("person_info") + +person_info_default = { + "person_id" : None, + "platform" : None, + "user_id" : None, + "nickname" : None, + # "age" : 0, + "relationship_value" : 0, + # "saved" : True, + # "impression" : None, + # "gender" : Unkown, + "konw_time" : 0, +} # 个人信息的各项与默认值在此定义,以下处理会自动创建/补全每一项 + +class PersonInfoManager: + def __init__(self): + if "person_info" not in db.list_collection_names(): + db.create_collection("person_info") + db.person_info.create_index("person_id", unique=True) + + def get_person_id(self, platform:str, user_id:int): + """获取唯一id""" + components = [platform, str(user_id)] + key = "_".join(components) + return hashlib.md5(key.encode()).hexdigest() + + async def create_person_info(self, person_id:str, data:dict = {}): + """创建一个项""" + if not person_id: + logger.debug("创建失败,personid不存在") + return + + _person_info_default = copy.deepcopy(person_info_default) + _person_info_default["person_id"] = person_id + + if data: + for key in _person_info_default: + if key != "person_id" and key in data: + _person_info_default[key] = data[key] + + db.person_info.insert_one(_person_info_default) + + async def update_one_field(self, person_id:str, field_name:str, value, Data:dict = {}): + """更新某一个字段,会补全""" + if not field_name in person_info_default.keys(): + logger.debug(f"更新'{field_name}'失败,未定义的字段") + return + + document = db.person_info.find_one({"person_id": person_id}) + + if document: + db.person_info.update_one( + {"person_id": person_id}, + {"$set": {field_name: value}} + ) + else: + Data[field_name] = value + logger.debug(f"更新时{person_id}不存在,已新建") + await self.create_person_info(person_id, Data) + + async def del_one_document(self, person_id: str): + """删除指定 person_id 的文档""" + if not person_id: + logger.debug("删除失败:person_id 不能为空") + return + + result = db.person_info.delete_one({"person_id": person_id}) + if result.deleted_count > 0: + logger.debug(f"删除成功:person_id={person_id}") + else: + logger.debug(f"删除失败:未找到 person_id={person_id}") + + async def get_value(self, person_id: str, field_name: str): + """获取指定person_id文档的字段值,若不存在该字段,则返回该字段的全局默认值""" + if not person_id: + logger.debug("get_value获取失败:person_id不能为空") + return None + + if field_name not in person_info_default: + logger.debug(f"get_value获取失败:字段'{field_name}'未定义") + return None + + document = db.person_info.find_one( + {"person_id": person_id}, + {field_name: 1} + ) + + if document and field_name in document: + return document[field_name] + else: + logger.debug(f"获取{person_id}的{field_name}失败,已返回默认值{person_info_default[field_name]}") + return person_info_default[field_name] + + async def get_values(self, person_id: str, field_names: list) -> dict: + """获取指定person_id文档的多个字段值,若不存在该字段,则返回该字段的全局默认值""" + if not person_id: + logger.debug("get_values获取失败:person_id不能为空") + return {} + + # 检查所有字段是否有效 + for field in field_names: + if field not in person_info_default: + logger.debug(f"get_values获取失败:字段'{field}'未定义") + return {} + + # 构建查询投影(所有字段都有效才会执行到这里) + projection = {field: 1 for field in field_names} + + document = db.person_info.find_one( + {"person_id": person_id}, + projection + ) + + result = {} + for field in field_names: + result[field] = document.get(field, person_info_default[field]) if document else person_info_default[field] + + return result + + async def del_all_undefined_field(self): + """删除所有项里的未定义字段""" + # 获取所有已定义的字段名 + defined_fields = set(person_info_default.keys()) + + try: + # 遍历集合中的所有文档 + for document in db.person_info.find({}): + # 找出文档中未定义的字段 + undefined_fields = set(document.keys()) - defined_fields - {'_id'} + + if undefined_fields: + # 构建更新操作,使用$unset删除未定义字段 + update_result = db.person_info.update_one( + {'_id': document['_id']}, + {'$unset': {field: 1 for field in undefined_fields}} + ) + + if update_result.modified_count > 0: + logger.debug(f"已清理文档 {document['_id']} 的未定义字段: {undefined_fields}") + + return + + except Exception as e: + logger.error(f"清理未定义字段时出错: {e}") + return + + async def get_specific_value_list( + self, + field_name: str, + way: Callable[[Any], bool], # 接受任意类型值 +) ->Dict[str, Any]: + """ + 获取满足条件的字段值字典 + + Args: + field_name: 目标字段名 + way: 判断函数 (value: Any) -> bool + convert_type: 强制类型转换(如float/int等) + + Returns: + {person_id: value} | {} + + Example: + # 查找所有nickname包含"admin"的用户 + result = manager.specific_value_list( + "nickname", + lambda x: "admin" in x.lower() + ) + """ + if field_name not in person_info_default: + logger.error(f"字段检查失败:'{field_name}'未定义") + return {} + + try: + result = {} + for doc in db.person_info.find( + {field_name: {"$exists": True}}, + {"person_id": 1, field_name: 1, "_id": 0} + ): + try: + value = doc[field_name] + if way(value): + result[doc["person_id"]] = value + except (KeyError, TypeError, ValueError) as e: + logger.debug(f"记录{doc.get('person_id')}处理失败: {str(e)}") + continue + + return result + + except Exception as e: + logger.error(f"数据库查询失败: {str(e)}", exc_info=True) + return {} + +person_info_manager = PersonInfoManager() \ No newline at end of file From 8f22612d38dc2eb0c6a7ea61de386c2b4571bb20 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 00:32:22 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E5=A4=8D=E6=B4=BB=E5=90=A7=EF=BC=81?= =?UTF-8?q?=E6=88=91=E7=9A=84=E5=85=B3=E7=B3=BB=E7=B3=BB=E7=BB=9F=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=AD=A3=E5=8F=8D=E9=A6=88=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/relationship_manager.py | 343 +++++------------------ 1 file changed, 76 insertions(+), 267 deletions(-) diff --git a/src/plugins/chat/relationship_manager.py b/src/plugins/chat/relationship_manager.py index 9221817c3..bb9c78353 100644 --- a/src/plugins/chat/relationship_manager.py +++ b/src/plugins/chat/relationship_manager.py @@ -1,12 +1,9 @@ -import asyncio -from typing import Optional from src.common.logger import get_module_logger, LogConfig, RELATION_STYLE_CONFIG - -from ...common.database import db -from ..message.message_base import UserInfo from .chat_stream import ChatStream import math from bson.decimal128 import Decimal128 +from .person_info import person_info_manager +import time relationship_config = LogConfig( # 使用关系专用样式 @@ -15,287 +12,89 @@ relationship_config = LogConfig( ) logger = get_module_logger("rel_manager", config=relationship_config) - -class Impression: - traits: str = None - called: str = None - know_time: float = None - - relationship_value: float = None - - -class Relationship: - user_id: int = None - platform: str = None - gender: str = None - age: int = None - nickname: str = None - relationship_value: float = None - saved = False - - def __init__(self, chat: ChatStream = None, data: dict = None): - self.user_id = chat.user_info.user_id if chat else data.get("user_id", 0) - self.platform = chat.platform if chat else data.get("platform", "") - self.nickname = chat.user_info.user_nickname if chat else data.get("nickname", "") - self.relationship_value = data.get("relationship_value", 0) if data else 0 - self.age = data.get("age", 0) if data else 0 - self.gender = data.get("gender", "") if data else "" - - class RelationshipManager: def __init__(self): - self.relationships: dict[tuple[int, str], Relationship] = {} # 修改为使用(user_id, platform)作为键 + self.positive_feedback_dict = {} # 正反馈系统 - async def update_relationship(self, chat_stream: ChatStream, data: dict = None, **kwargs) -> Optional[Relationship]: - """更新或创建关系 - Args: - chat_stream: 聊天流对象 - data: 字典格式的数据(可选) - **kwargs: 其他参数 - Returns: - Relationship: 关系对象 - """ - # 确定user_id和platform - if chat_stream.user_info is not None: - user_id = chat_stream.user_info.user_id - platform = chat_stream.user_info.platform or "qq" + def positive_feedback_sys(self, person_id, value, label: str, stance: str): + """正反馈系统""" + + positive_list = [ + "开心", + "惊讶", + "害羞", + "困惑", + ] + + negative_list = [ + "愤怒", + "悲伤", + "恐惧", + "厌恶", + ] + + if person_id not in self.positive_feedback_dict: + self.positive_feedback_dict[person_id] = 0 + + if label in positive_list and stance != "反对": + if 6 > self.positive_feedback_dict[person_id] >= 0: + self.positive_feedback_dict[person_id] += 1 + elif self.positive_feedback_dict[person_id] < 0: + self.positive_feedback_dict[person_id] = 0 + return value + elif label in negative_list and stance != "支持": + if -6 < self.positive_feedback_dict[person_id] <= 0: + self.positive_feedback_dict[person_id] -= 1 + elif self.positive_feedback_dict[person_id] > 0: + self.positive_feedback_dict[person_id] = 0 + return value else: - platform = platform or "qq" + return value - if user_id is None: - raise ValueError("必须提供user_id或user_info") + gain_coefficient = [1.1, 1.2, 1.4, 1.7, 1.9, 2.0] + value *= gain_coefficient[abs(self.positive_feedback_dict[person_id])-1] + logger.info(f"触发增益,当前增益系数:{gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]}") - # 使用(user_id, platform)作为键 - key = (user_id, platform) + return value - # 检查是否在内存中已存在 - relationship = self.relationships.get(key) - if relationship: - # 如果存在,更新现有对象 - if isinstance(data, dict): - for k, value in data.items(): - if hasattr(relationship, k) and value is not None: - setattr(relationship, k, value) - else: - # 如果不存在,创建新对象 - if chat_stream.user_info is not None: - relationship = Relationship(chat=chat_stream, **kwargs) - else: - raise ValueError("必须提供user_id或user_info") - self.relationships[key] = relationship - - # 保存到数据库 - await self.storage_relationship(relationship) - relationship.saved = True - - return relationship - - async def update_relationship_value(self, chat_stream: ChatStream, **kwargs) -> Optional[Relationship]: - """更新关系值 - Args: - user_id: 用户ID(可选,如果提供user_info则不需要) - platform: 平台(可选,如果提供user_info则不需要) - user_info: 用户信息对象(可选) - **kwargs: 其他参数 - Returns: - Relationship: 关系对象 - """ - # 确定user_id和platform - user_info = chat_stream.user_info - if user_info is not None: - user_id = user_info.user_id - platform = user_info.platform or "qq" - else: - platform = platform or "qq" - - if user_id is None: - raise ValueError("必须提供user_id或user_info") - - # 使用(user_id, platform)作为键 - key = (user_id, platform) - - # 检查是否在内存中已存在 - relationship = self.relationships.get(key) - if relationship: - for k, value in kwargs.items(): - if k == "relationship_value": - # 检查relationship.relationship_value是否为double类型 - if not isinstance(relationship.relationship_value, float): - try: - # 处理 Decimal128 类型 - if isinstance(relationship.relationship_value, Decimal128): - relationship.relationship_value = float(relationship.relationship_value.to_decimal()) - else: - relationship.relationship_value = float(relationship.relationship_value) - logger.info( - f"[关系管理] 用户 {user_id}({platform}) 的关系值已转换为double类型: {relationship.relationship_value}" - ) # noqa: E501 - except (ValueError, TypeError): - # 如果不能解析/强转则将relationship.relationship_value设置为double类型的0 - relationship.relationship_value = 0.0 - logger.warning(f"[关系管理] 用户 {user_id}({platform}) 的无法转换为double类型,已设置为0") - relationship.relationship_value += value - await self.storage_relationship(relationship) - relationship.saved = True - return relationship - else: - # 如果不存在且提供了user_info,则创建新的关系 - if user_info is not None: - return await self.update_relationship(chat_stream=chat_stream, **kwargs) - logger.warning(f"[关系管理] 用户 {user_id}({platform}) 不存在,无法更新") - return None - - def get_relationship(self, chat_stream: ChatStream) -> Optional[Relationship]: - """获取用户关系对象 - Args: - user_id: 用户ID(可选,如果提供user_info则不需要) - platform: 平台(可选,如果提供user_info则不需要) - user_info: 用户信息对象(可选) - Returns: - Relationship: 关系对象 - """ - # 确定user_id和platform - user_info = chat_stream.user_info - platform = chat_stream.user_info.platform or "qq" - if user_info is not None: - user_id = user_info.user_id - platform = user_info.platform or "qq" - else: - platform = platform or "qq" - - if user_id is None: - raise ValueError("必须提供user_id或user_info") - - key = (user_id, platform) - if key in self.relationships: - return self.relationships[key] - else: - return None - - async def load_relationship(self, data: dict) -> Relationship: - """从数据库加载或创建新的关系对象""" - # 确保data中有platform字段,如果没有则默认为'qq' - if "platform" not in data: - data["platform"] = "qq" - - rela = Relationship(data=data) - rela.saved = True - key = (rela.user_id, rela.platform) - self.relationships[key] = rela - return rela - - async def load_all_relationships(self): - """加载所有关系对象""" - all_relationships = db.relationships.find({}) - for data in all_relationships: - await self.load_relationship(data) - - async def _start_relationship_manager(self): - """每5分钟自动保存一次关系数据""" - # 获取所有关系记录 - all_relationships = db.relationships.find({}) - # 依次加载每条记录 - for data in all_relationships: - await self.load_relationship(data) - logger.debug(f"[关系管理] 已加载 {len(self.relationships)} 条关系记录") - - while True: - logger.debug("正在自动保存关系") - await asyncio.sleep(300) # 等待300秒(5分钟) - await self._save_all_relationships() - - async def _save_all_relationships(self): - """将所有关系数据保存到数据库""" - # 保存所有关系数据 - for _, relationship in self.relationships.items(): - if not relationship.saved: - relationship.saved = True - await self.storage_relationship(relationship) - - async def storage_relationship(self, relationship: Relationship): - """将关系记录存储到数据库中""" - user_id = relationship.user_id - platform = relationship.platform - nickname = relationship.nickname - relationship_value = relationship.relationship_value - gender = relationship.gender - age = relationship.age - saved = relationship.saved - - db.relationships.update_one( - {"user_id": user_id, "platform": platform}, - { - "$set": { - "platform": platform, - "nickname": nickname, - "relationship_value": relationship_value, - "gender": gender, - "age": age, - "saved": saved, - } - }, - upsert=True, - ) - - def get_name(self, user_id: int = None, platform: str = None, user_info: UserInfo = None) -> str: - """获取用户昵称 - Args: - user_id: 用户ID(可选,如果提供user_info则不需要) - platform: 平台(可选,如果提供user_info则不需要) - user_info: 用户信息对象(可选) - Returns: - str: 用户昵称 - """ - # 确定user_id和platform - if user_info is not None: - user_id = user_info.user_id - platform = user_info.platform or "qq" - else: - platform = platform or "qq" - - if user_id is None: - raise ValueError("必须提供user_id或user_info") - - # 确保user_id是整数类型 - user_id = int(user_id) - key = (user_id, platform) - if key in self.relationships: - return self.relationships[key].nickname - elif user_info is not None: - 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.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢 + 4.连续正面或负面情感会正反馈 """ stancedict = { "支持": 0, "中立": 1, "反对": 2, } - + valuedict = { "开心": 1.5, - "愤怒": -3.5, - "悲伤": -1.5, + "愤怒": -2.0, + "悲伤": -0.5, "惊讶": 0.6, "害羞": 2.0, "平静": 0.3, - "恐惧": -2, - "厌恶": -2.5, + "恐惧": -1.5, + "厌恶": -1.0, "困惑": 0.5, } - if self.get_relationship(chat_stream): - old_value = self.get_relationship(chat_stream).relationship_value - else: - return + + person_id = person_info_manager.get_person_id(chat_stream.user_info.platform, chat_stream.user_info.user_id) + data = { + "platform" : chat_stream.user_info.platform, + "user_id" : chat_stream.user_info.user_id, + "nickname" : chat_stream.user_info.user_nickname, + "konw_time" : int(time.time()) + } + old_value = await person_info_manager.get_value(person_id, "relationship_value") + old_value = self.ensure_float(old_value, person_id) if old_value > 1000: old_value = 1000 @@ -307,26 +106,26 @@ class RelationshipManager: 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 _, relationship in self.relationships.items(): - if relationship.relationship_value >= 700: - high_value_count += 1 - if old_value >= 700: + rdict = await person_info_manager.get_specific_value_list("relationship_value", lambda x: x > 700) + high_value_count = len(rdict) + if old_value > 700: value *= 3 / (high_value_count + 2) # 排除自己 else: value *= 3 / (high_value_count + 3) elif valuedict[label] < 0 and stancedict[stance] != 0: - value = value * math.exp(old_value / 1000) + value = value * math.exp(old_value / 2000) else: value = 0 elif old_value < 0: if valuedict[label] >= 0 and stancedict[stance] != 2: - value = value * math.exp(old_value / 1000) + value = value * math.exp(old_value / 2000) elif valuedict[label] < 0 and stancedict[stance] != 0: value = value * math.cos(math.pi * old_value / 2000) else: value = 0 + value = self.positive_feedback_sys(person_id, value, label, stance) + level_num = self.calculate_level_num(old_value + value) relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] logger.info( @@ -336,10 +135,11 @@ class RelationshipManager: f"变更: {value:+.5f}" ) - await self.update_relationship_value(chat_stream=chat_stream, relationship_value=value) + await person_info_manager.update_one_field(person_id, "relationship_value", old_value + value, data) def build_relationship_info(self, person) -> str: - relationship_value = relationship_manager.get_relationship(person).relationship_value + person_id = person_info_manager.get_person_id(person.user_info.platform, person.user_info.user_id) + relationship_value = person_info_manager.get_value(person_id, "relationship_value") level_num = self.calculate_level_num(relationship_value) relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] relation_prompt2_list = [ @@ -379,5 +179,14 @@ class RelationshipManager: level_num = 5 if relationship_value > 1000 else 0 return level_num + def ensure_float(elsf, value, person_id): + """确保返回浮点数,转换失败返回0.0""" + if isinstance(value, float): + return value + try: + return float(value.to_decimal() if isinstance(value, Decimal128) else value) + except (ValueError, TypeError, AttributeError): + logger.warning(f"[关系管理] {person_id}值转换失败(原始值:{value}),已重置为0") + return 0.0 relationship_manager = RelationshipManager() From af6f23615ebf5da1029a896ee260f7ce61da1c13 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 01:09:05 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=A2=9E=E7=9B=8A?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/relationship_manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/chat/relationship_manager.py b/src/plugins/chat/relationship_manager.py index bb9c78353..2e58cd4b9 100644 --- a/src/plugins/chat/relationship_manager.py +++ b/src/plugins/chat/relationship_manager.py @@ -23,7 +23,6 @@ class RelationshipManager: "开心", "惊讶", "害羞", - "困惑", ] negative_list = [ @@ -37,13 +36,13 @@ class RelationshipManager: self.positive_feedback_dict[person_id] = 0 if label in positive_list and stance != "反对": - if 6 > self.positive_feedback_dict[person_id] >= 0: + if 7 > self.positive_feedback_dict[person_id] >= 0: self.positive_feedback_dict[person_id] += 1 elif self.positive_feedback_dict[person_id] < 0: self.positive_feedback_dict[person_id] = 0 return value elif label in negative_list and stance != "支持": - if -6 < self.positive_feedback_dict[person_id] <= 0: + if -7 < self.positive_feedback_dict[person_id] <= 0: self.positive_feedback_dict[person_id] -= 1 elif self.positive_feedback_dict[person_id] > 0: self.positive_feedback_dict[person_id] = 0 @@ -51,9 +50,10 @@ class RelationshipManager: else: return value - gain_coefficient = [1.1, 1.2, 1.4, 1.7, 1.9, 2.0] + gain_coefficient = [1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0] value *= gain_coefficient[abs(self.positive_feedback_dict[person_id])-1] - logger.info(f"触发增益,当前增益系数:{gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]}") + if abs(self.positive_feedback_dict[person_id]) - 1: + logger.info(f"触发增益,当前增益系数:{gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]}") return value From 4cce44bcedcfe76a659ec77a6478e56a2f111419 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 02:50:48 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=85=B3=E7=B3=BB?= =?UTF-8?q?=E7=9A=84prompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/prompt_builder.py | 26 +++++++++++++++++++++--- src/plugins/chat/relationship_manager.py | 23 ++++++++------------- src/plugins/chat/utils.py | 18 +++++++--------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/plugins/chat/prompt_builder.py b/src/plugins/chat/prompt_builder.py index cc048fc70..37da5dd4f 100644 --- a/src/plugins/chat/prompt_builder.py +++ b/src/plugins/chat/prompt_builder.py @@ -7,9 +7,10 @@ from ..memory_system.Hippocampus import HippocampusManager from ..moods.moods import MoodManager from ..schedule.schedule_generator import bot_schedule from ..config.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 src.common.logger import get_module_logger +from .relationship_manager import relationship_manager from src.heart_flow.heartflow import heartflow @@ -29,6 +30,25 @@ class PromptBuilder: # 开始构建prompt + # 关系 + who_chat_in_group = [(chat_stream.user_info.platform, + chat_stream.user_info.user_id, + chat_stream.user_info.user_nickname)] + who_chat_in_group += get_recent_group_speaker( + stream_id, + (chat_stream.user_info.platform, chat_stream.user_info.user_id), + limit=global_config.MAX_CONTEXT_SIZE, + ) + + relation_prompt = "" + for person in who_chat_in_group: + relation_prompt += await relationship_manager.build_relationship_info(person) + + relation_prompt_all = ( + f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录," + f"根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。" + ) + # 心情 mood_manager = MoodManager.get_instance() mood_prompt = mood_manager.get_prompt() @@ -116,14 +136,14 @@ class PromptBuilder: {chat_talking_prompt} 你刚刚脑子里在想: {current_mind_info} -现在"{sender_name}"说的:{message_txt}。引起了你的注意,你想要在群里发言发言或者回复这条消息。\n +现在"{sender_name}"说的:{message_txt}。引起了你的注意,你想要在群里发言发言或者回复这条消息。{relation_prompt_all}\n 你的网名叫{global_config.BOT_NICKNAME},有人也叫你{"/".join(global_config.BOT_ALIAS_NAMES)},{prompt_personality}。 你正在{chat_target_2},现在请你读读之前的聊天记录,然后给出日常且口语化的回复,平淡一些, 尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。{prompt_ger} 请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,尽量不要说你说过的话 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。 {moderation_prompt}不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。""" - + return prompt 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 2e58cd4b9..ddc172264 100644 --- a/src/plugins/chat/relationship_manager.py +++ b/src/plugins/chat/relationship_manager.py @@ -137,29 +137,24 @@ class RelationshipManager: await person_info_manager.update_one_field(person_id, "relationship_value", old_value + value, data) - def build_relationship_info(self, person) -> str: - person_id = person_info_manager.get_person_id(person.user_info.platform, person.user_info.user_id) - relationship_value = person_info_manager.get_value(person_id, "relationship_value") + async def build_relationship_info(self, person) -> str: + person_id = person_info_manager.get_person_id(person[0], person[1]) + relationship_value = await person_info_manager.get_value(person_id, "relationship_value") level_num = self.calculate_level_num(relationship_value) 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}。" - ) + + return ( + f"你对昵称为'({person[1]}){person[2]}'的用户的态度为{relationship_level[level_num]}," + f"回复态度为{relation_prompt2_list[level_num]},关系等级为{level_num}。" + ) def calculate_level_num(self, relationship_value) -> int: """关系等级计算""" diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index ecd67816a..bcf79063a 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -149,7 +149,6 @@ def get_recent_group_speaker(chat_stream_id: int, sender, limit: int = 12) -> li db.messages.find( {"chat_id": chat_stream_id}, { - "chat_info": 1, "user_info": 1, }, ) @@ -160,20 +159,17 @@ def get_recent_group_speaker(chat_stream_id: int, sender, limit: int = 12) -> li if not recent_messages: return [] - who_chat_in_group = [] # ChatStream列表 - - duplicate_removal = [] + who_chat_in_group = [] 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 + (user_info.platform, user_info.user_id) != sender + and user_info.user_id != global_config.BOT_QQ + and (user_info.platform, user_info.user_id, user_info.user_nickname) not in who_chat_in_group + and len(who_chat_in_group) < 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)) + who_chat_in_group.append((user_info.platform, user_info.user_id, user_info.user_nickname)) + return who_chat_in_group From 59043abefc68a547d7a4733cae7d79f7fa09c62f Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 04:20:53 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E4=B8=BA=E5=86=B2=E7=AA=81=E5=AF=BC=E8=87=B4=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 3 +-- src/plugins/__init__.py | 2 +- src/plugins/chat/__init__.py | 2 +- src/plugins/chat/utils.py | 11 ++++++++++- .../think_flow_chat/think_flow_chat.py | 15 +++++++++++++++ .../think_flow_chat/think_flow_generator.py | 2 ++ .../think_flow_chat/think_flow_prompt_builder.py | 4 ++-- src/plugins/{chat => person_info}/person_info.py | 0 .../relationship_manager.py | 2 +- 9 files changed, 33 insertions(+), 8 deletions(-) rename src/plugins/{chat => person_info}/person_info.py (100%) rename src/plugins/{relationship => person_info}/relationship_manager.py (99%) diff --git a/src/main.py b/src/main.py index 177027d4e..af2896c79 100644 --- a/src/main.py +++ b/src/main.py @@ -4,8 +4,7 @@ from .plugins.utils.statistic import LLMStatistics from .plugins.moods.moods import MoodManager from .plugins.schedule.schedule_generator import bot_schedule from .plugins.chat.emoji_manager import emoji_manager -from .plugins.chat.person_info import person_info_manager -from .plugins.relationship.relationship_manager import relationship_manager +from .plugins.person_info.person_info import person_info_manager from .plugins.willing.willing_manager import willing_manager from .plugins.chat.chat_stream import chat_manager from .heart_flow.heartflow import heartflow diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py index 186245417..1bc844939 100644 --- a/src/plugins/__init__.py +++ b/src/plugins/__init__.py @@ -5,7 +5,7 @@ MaiMBot插件系统 from .chat.chat_stream import chat_manager from .chat.emoji_manager import emoji_manager -from .relationship.relationship_manager import relationship_manager +from .person_info.relationship_manager import relationship_manager from .moods.moods import MoodManager from .willing.willing_manager import willing_manager from .schedule.schedule_generator import bot_schedule diff --git a/src/plugins/chat/__init__.py b/src/plugins/chat/__init__.py index 0f4dada44..e5cef56a5 100644 --- a/src/plugins/chat/__init__.py +++ b/src/plugins/chat/__init__.py @@ -1,5 +1,5 @@ from .emoji_manager import emoji_manager -from ..relationship.relationship_manager import relationship_manager +from ..person_info.relationship_manager import relationship_manager from .chat_stream import chat_manager from .message_sender import message_manager from ..storage.storage import MessageStorage diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 188fe924b..c575eea88 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -167,7 +167,7 @@ def get_recent_group_speaker(chat_stream_id: int, sender, limit: int = 12) -> li and user_info.user_id != global_config.BOT_QQ and (user_info.platform, user_info.user_id, user_info.user_nickname) not in who_chat_in_group and len(who_chat_in_group) < 5 - ): # 排除重复,排除消息发送者,排除bot(此处bot的平台强制为了qq,可能需要更改),限制加载的关系数目 + ): # 排除重复,排除消息发送者,排除bot,限制加载的关系数目 who_chat_in_group.append((user_info.platform, user_info.user_id, user_info.user_nickname)) return who_chat_in_group @@ -345,6 +345,15 @@ def calculate_typing_time(input_string: str, chinese_time: float = 0.2, english_ - 如果只有一个中文字符,将使用3倍的中文输入时间 - 在所有输入结束后,额外加上回车时间0.3秒 """ + + # 如果输入是列表,将其连接成字符串 + if isinstance(input_string, list): + input_string = ''.join(input_string) + + # 确保现在是字符串类型 + if not isinstance(input_string, str): + input_string = str(input_string) + mood_manager = MoodManager.get_instance() # 将0-1的唤醒度映射到-1到1 mood_arousal = mood_manager.current_mood.arousal diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index f665d90fd..19247dc2c 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -17,6 +17,7 @@ from ...message import UserInfo, Seg from src.heart_flow.heartflow import heartflow from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig from ...chat.chat_stream import chat_manager +from ...person_info.relationship_manager import relationship_manager # 定义日志配置 chat_config = LogConfig( @@ -135,6 +136,14 @@ class ThinkFlowChat: await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt) + async def _update_relationship(self, message, response_set): + """更新关系""" + ori_response = ",".join(response_set) + stance, emotion = await self.gpt._get_emotion_tags(ori_response, message.processed_plain_text) + await relationship_manager.calculate_update_relationship_value( + chat_stream=message.chat_stream, label=emotion, stance=stance + ) + async def process_message(self, message_data: str) -> None: """处理消息并生成回复""" timing_results = {} @@ -267,6 +276,12 @@ class ThinkFlowChat: timer2 = time.time() timing_results["更新心流"] = timer2 - timer1 + # # 更新关系 + # timer1 = time.time() + # await self._update_relationship(message, response_set) + # timer2 = time.time() + # timing_results["更新关系"] = timer2 - timer1 + # 输出性能计时结果 if do_reply: timing_str = " | ".join([f"{step}: {duration:.2f}秒" for step, duration in timing_results.items()]) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index 491897bcb..107acb3c2 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -147,6 +147,8 @@ class ResponseGenerator: - 严格基于文字直接表达的对立关系判断 """ + logger.info(prompt) + # 调用模型生成结果 result, _, _ = await self.model_sum.generate_response(prompt) result = result.strip() diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py index c15990be1..cca3f0049 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py @@ -6,10 +6,10 @@ from ...memory_system.Hippocampus import HippocampusManager from ...moods.moods import MoodManager from ...schedule.schedule_generator import bot_schedule from ...config.config import global_config -from ...chat.utils import get_recent_group_detailed_plain_text +from ...chat.utils import get_recent_group_detailed_plain_text, get_recent_group_speaker from ...chat.chat_stream import chat_manager from src.common.logger import get_module_logger -from .relationship_manager import relationship_manager +from ...person_info.relationship_manager import relationship_manager from src.heart_flow.heartflow import heartflow diff --git a/src/plugins/chat/person_info.py b/src/plugins/person_info/person_info.py similarity index 100% rename from src/plugins/chat/person_info.py rename to src/plugins/person_info/person_info.py diff --git a/src/plugins/relationship/relationship_manager.py b/src/plugins/person_info/relationship_manager.py similarity index 99% rename from src/plugins/relationship/relationship_manager.py rename to src/plugins/person_info/relationship_manager.py index ddc172264..e1ca2c79d 100644 --- a/src/plugins/relationship/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -1,5 +1,5 @@ from src.common.logger import get_module_logger, LogConfig, RELATION_STYLE_CONFIG -from .chat_stream import ChatStream +from ..chat.chat_stream import ChatStream import math from bson.decimal128 import Decimal128 from .person_info import person_info_manager From 52e363700a740101a51c413b886bbc8f4fa353b6 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 04:35:09 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=81=97=E7=95=99?= =?UTF-8?q?=E5=86=B2=E7=AA=81=EF=BC=8C=E5=A4=8D=E6=B4=BB=E5=BF=83=E6=B5=81?= =?UTF-8?q?=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat_module/think_flow_chat/think_flow_chat.py | 10 +++++----- .../think_flow_chat/think_flow_generator.py | 7 ++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 19247dc2c..3bd5d7181 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -276,11 +276,11 @@ class ThinkFlowChat: timer2 = time.time() timing_results["更新心流"] = timer2 - timer1 - # # 更新关系 - # timer1 = time.time() - # await self._update_relationship(message, response_set) - # timer2 = time.time() - # timing_results["更新关系"] = timer2 - timer1 + # 更新关系 + timer1 = time.time() + await self._update_relationship(message, response_set) + timer2 = time.time() + timing_results["更新关系"] = timer2 - timer1 # 输出性能计时结果 if do_reply: diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index 107acb3c2..d7240d9a6 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -42,7 +42,6 @@ class ResponseGenerator: current_model = self.model_normal model_response = await self._generate_response_with_model(message, current_model) - undivided_response = model_response # print(f"raw_content: {model_response}") @@ -50,10 +49,10 @@ class ResponseGenerator: logger.info(f"{global_config.BOT_NICKNAME}的回复是:{model_response}") model_response = await self._process_response(model_response) - return model_response, undivided_response + return model_response else: logger.info(f"{self.current_model_type}思考,失败") - return None, None + return None async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request): sender_name = "" @@ -147,8 +146,6 @@ class ResponseGenerator: - 严格基于文字直接表达的对立关系判断 """ - logger.info(prompt) - # 调用模型生成结果 result, _, _ = await self.model_sum.generate_response(prompt) result = result.strip() From 7c51cbf027705f4b0686c670321fee9d5b3649b1 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 11:47:37 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E6=96=B0=E5=A2=9Emood=E4=B8=8Erelation?= =?UTF-8?q?=E7=9A=84=E7=9B=B8=E4=BA=92=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../think_flow_chat/think_flow_chat.py | 7 ++- src/plugins/moods/moods.py | 24 ++++---- .../person_info/relationship_manager.py | 56 +++++++++++-------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 3bd5d7181..6cbde1bac 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -137,12 +137,13 @@ class ThinkFlowChat: await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt) async def _update_relationship(self, message, response_set): - """更新关系""" + """更新关系情绪""" ori_response = ",".join(response_set) stance, emotion = await self.gpt._get_emotion_tags(ori_response, message.processed_plain_text) await relationship_manager.calculate_update_relationship_value( chat_stream=message.chat_stream, label=emotion, stance=stance ) + self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor) async def process_message(self, message_data: str) -> None: """处理消息并生成回复""" @@ -276,11 +277,11 @@ class ThinkFlowChat: timer2 = time.time() timing_results["更新心流"] = timer2 - timer1 - # 更新关系 + # 更新关系情绪 timer1 = time.time() await self._update_relationship(message, response_set) timer2 = time.time() - timing_results["更新关系"] = timer2 - timer1 + timing_results["更新关系情绪"] = timer2 - timer1 # 输出性能计时结果 if do_reply: diff --git a/src/plugins/moods/moods.py b/src/plugins/moods/moods.py index 8115ee1b9..39e13b937 100644 --- a/src/plugins/moods/moods.py +++ b/src/plugins/moods/moods.py @@ -5,6 +5,7 @@ from dataclasses import dataclass from ..config.config import global_config from src.common.logger import get_module_logger, LogConfig, MOOD_STYLE_CONFIG +from ..person_info.relationship_manager import relationship_manager mood_config = LogConfig( # 使用海马体专用样式 @@ -55,15 +56,15 @@ class MoodManager: # 情绪词映射表 (valence, arousal) self.emotion_map = { - "开心": (0.8, 0.6), # 高愉悦度,中等唤醒度 - "愤怒": (-0.7, 0.7), # 负愉悦度,高唤醒度 - "悲伤": (-0.6, 0.3), # 负愉悦度,低唤醒度 - "惊讶": (0.2, 0.8), # 中等愉悦度,高唤醒度 - "害羞": (0.5, 0.2), # 中等愉悦度,低唤醒度 - "平静": (0.0, 0.5), # 中性愉悦度,中等唤醒度 - "恐惧": (-0.7, 0.6), # 负愉悦度,高唤醒度 - "厌恶": (-0.4, 0.4), # 负愉悦度,低唤醒度 - "困惑": (0.0, 0.6), # 中性愉悦度,高唤醒度 + "开心": (0.21, 0.6), + "害羞": (0.15, 0.2), + "愤怒": (-0.24, 0.8), + "恐惧": (-0.21, 0.7), + "悲伤": (-0.21, 0.3), + "厌恶": (-0.12, 0.4), + "惊讶": (0.06, 0.7), + "困惑": (0.0, 0.6), + "平静": (0.03, 0.5), } # 情绪文本映射表 @@ -93,7 +94,7 @@ class MoodManager: cls._instance = MoodManager() return cls._instance - def start_mood_update(self, update_interval: float = 1.0) -> None: + def start_mood_update(self, update_interval: float = 5.0) -> None: """ 启动情绪更新线程 :param update_interval: 更新间隔(秒) @@ -232,6 +233,8 @@ class MoodManager: valence_change, arousal_change = self.emotion_map[emotion] + valence_change *= relationship_manager.gain_coefficient[relationship_manager.positive_feedback_value] + # 应用情绪强度 valence_change *= intensity arousal_change *= intensity @@ -245,3 +248,4 @@ class MoodManager: self.current_mood.arousal = max(0.0, min(1.0, self.current_mood.arousal)) self._update_mood_text() + diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index e1ca2c79d..0b2f8fa67 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -14,10 +14,19 @@ logger = get_module_logger("rel_manager", config=relationship_config) class RelationshipManager: def __init__(self): - self.positive_feedback_dict = {} # 正反馈系统 + self.positive_feedback_value = 0 # 正反馈系统 + self.gain_coefficient = [1.0, 1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0] + self._mood_manager = None - def positive_feedback_sys(self, person_id, value, label: str, stance: str): - """正反馈系统""" + @property + def mood_manager(self): + if self._mood_manager is None: + from ..moods.moods import MoodManager # 延迟导入 + self._mood_manager = MoodManager.get_instance() + return self._mood_manager + + def positive_feedback_sys(self, label: str, stance: str): + """正反馈系统,通过正反馈系数增益情绪变化,根据情绪再影响关系变更""" positive_list = [ "开心", @@ -32,29 +41,27 @@ class RelationshipManager: "厌恶", ] - if person_id not in self.positive_feedback_dict: - self.positive_feedback_dict[person_id] = 0 - if label in positive_list and stance != "反对": - if 7 > self.positive_feedback_dict[person_id] >= 0: - self.positive_feedback_dict[person_id] += 1 - elif self.positive_feedback_dict[person_id] < 0: - self.positive_feedback_dict[person_id] = 0 - return value + if 7 > self.positive_feedback_value >= 0: + self.positive_feedback_value += 1 + elif self.positive_feedback_value < 0: + self.positive_feedback_value = 0 elif label in negative_list and stance != "支持": - if -7 < self.positive_feedback_dict[person_id] <= 0: - self.positive_feedback_dict[person_id] -= 1 - elif self.positive_feedback_dict[person_id] > 0: - self.positive_feedback_dict[person_id] = 0 - return value - else: - return value - - gain_coefficient = [1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0] - value *= gain_coefficient[abs(self.positive_feedback_dict[person_id])-1] - if abs(self.positive_feedback_dict[person_id]) - 1: - logger.info(f"触发增益,当前增益系数:{gain_coefficient[abs(self.positive_feedback_dict[person_id])-1]}") + if -7 < self.positive_feedback_value <= 0: + self.positive_feedback_value -= 1 + elif self.positive_feedback_value > 0: + self.positive_feedback_value = 0 + + if abs(self.positive_feedback_value) > 1: + logger.info(f"触发mood变更增益,当前增益系数:{self.gain_coefficient[abs(self.positive_feedback_value)]}") + def mood_feedback(self, value): + """情绪反馈""" + mood_manager = self.mood_manager + mood_gain = (mood_manager.get_current_mood().valence) ** 2 \ + * math.copysign(1, value * mood_manager.get_current_mood().valence) + value += value * mood_gain + logger.info(f"当前relationship增益系数:{mood_gain:.3f}") return value @@ -124,7 +131,8 @@ class RelationshipManager: else: value = 0 - value = self.positive_feedback_sys(person_id, value, label, stance) + self.positive_feedback_sys(label, stance) + value = self.mood_feedback(value) level_num = self.calculate_level_num(old_value + value) relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] From 8179b7153ab66da27b1f7a6279c16a0c6effa24b Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 11:59:37 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E5=A4=8D=E6=B4=BB=E6=8E=A8=E7=90=86?= =?UTF-8?q?=E7=9A=84=E5=85=B3=E7=B3=BB=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reasoning_chat/reasoning_chat.py | 16 +++++++++++++ .../reasoning_prompt_builder.py | 24 +++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py index 6ad043804..2a6561d83 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py @@ -16,6 +16,7 @@ from ...willing.willing_manager import willing_manager from ...message import UserInfo, Seg from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig from ...chat.chat_stream import chat_manager +from ...person_info.relationship_manager import relationship_manager # 定义日志配置 chat_config = LogConfig( @@ -123,6 +124,15 @@ class ReasoningChat: ) message_manager.add_message(bot_message) + async def _update_relationship(self, message, response_set): + """更新关系情绪""" + ori_response = ",".join(response_set) + stance, emotion = await self.gpt._get_emotion_tags(ori_response, message.processed_plain_text) + await relationship_manager.calculate_update_relationship_value( + chat_stream=message.chat_stream, label=emotion, stance=stance + ) + self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor) + async def process_message(self, message_data: str) -> None: """处理消息并生成回复""" timing_results = {} @@ -231,6 +241,12 @@ class ReasoningChat: timer2 = time.time() timing_results["处理表情包"] = timer2 - timer1 + # 更新关系情绪 + timer1 = time.time() + await self._update_relationship(message, response_set) + timer2 = time.time() + timing_results["更新关系情绪"] = timer2 - timer1 + # 输出性能计时结果 if do_reply: timing_str = " | ".join([f"{step}: {duration:.2f}秒" for step, duration in timing_results.items()]) diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_prompt_builder.py b/src/plugins/chat_module/reasoning_chat/reasoning_prompt_builder.py index 508febec8..e3015fe1e 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_prompt_builder.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_prompt_builder.py @@ -7,9 +7,10 @@ from ...memory_system.Hippocampus import HippocampusManager from ...moods.moods import MoodManager from ...schedule.schedule_generator import bot_schedule from ...config.config import global_config -from ...chat.utils import get_embedding, get_recent_group_detailed_plain_text +from ...chat.utils import get_embedding, get_recent_group_detailed_plain_text, get_recent_group_speaker from ...chat.chat_stream import chat_manager from src.common.logger import get_module_logger +from ...person_info.relationship_manager import relationship_manager logger = get_module_logger("prompt") @@ -25,6 +26,25 @@ class PromptBuilder: # 开始构建prompt + # 关系 + who_chat_in_group = [(chat_stream.user_info.platform, + chat_stream.user_info.user_id, + chat_stream.user_info.user_nickname)] + who_chat_in_group += get_recent_group_speaker( + stream_id, + (chat_stream.user_info.platform, chat_stream.user_info.user_id), + limit=global_config.MAX_CONTEXT_SIZE, + ) + + relation_prompt = "" + for person in who_chat_in_group: + relation_prompt += await relationship_manager.build_relationship_info(person) + + relation_prompt_all = ( + f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录," + f"根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。" + ) + # 心情 mood_manager = MoodManager.get_instance() mood_prompt = mood_manager.get_prompt() @@ -127,7 +147,7 @@ class PromptBuilder: {schedule_prompt} {chat_target} {chat_talking_prompt} -现在"{sender_name}"说的:{message_txt}。引起了你的注意,你想要在群里发言发言或者回复这条消息。\n +现在"{sender_name}"说的:{message_txt}。引起了你的注意,你想要在群里发言发言或者回复这条消息。{relation_prompt_all}\n 你的网名叫{global_config.BOT_NICKNAME},有人也叫你{"/".join(global_config.BOT_ALIAS_NAMES)},{prompt_personality}。 你正在{chat_target_2},现在请你读读之前的聊天记录,{mood_prompt},然后给出日常且口语化的回复,平淡一些, 尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。{prompt_ger} From 82351b436c4a04549b64bc8c27ea4f131bdd8c21 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Wed, 2 Apr 2025 12:40:08 +0800 Subject: [PATCH 09/13] ruff --- src/plugins/person_info/person_info.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 28e515971..f940c0fca 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -44,7 +44,7 @@ class PersonInfoManager: key = "_".join(components) return hashlib.md5(key.encode()).hexdigest() - async def create_person_info(self, person_id:str, data:dict = {}): + async def create_person_info(self, person_id:str, data:dict = None): """创建一个项""" if not person_id: logger.debug("创建失败,personid不存在") @@ -60,9 +60,9 @@ class PersonInfoManager: db.person_info.insert_one(_person_info_default) - async def update_one_field(self, person_id:str, field_name:str, value, Data:dict = {}): + async def update_one_field(self, person_id:str, field_name:str, value, Data:dict = None): """更新某一个字段,会补全""" - if not field_name in person_info_default.keys(): + if field_name not in person_info_default.keys(): logger.debug(f"更新'{field_name}'失败,未定义的字段") return @@ -175,7 +175,6 @@ class PersonInfoManager: Args: field_name: 目标字段名 way: 判断函数 (value: Any) -> bool - convert_type: 强制类型转换(如float/int等) Returns: {person_id: value} | {} From 56f8016938b2b76f785c0ea6da86c07c7f6cffe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E6=BA=AA=E7=95=94?= <130263765+na10xi27da@users.noreply.github.com> Date: Wed, 2 Apr 2025 13:41:07 +0800 Subject: [PATCH 10/13] typo --- src/plugins/person_info/relationship_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 0b2f8fa67..707dbbe51 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -182,7 +182,7 @@ class RelationshipManager: level_num = 5 if relationship_value > 1000 else 0 return level_num - def ensure_float(elsf, value, person_id): + def ensure_float(self, value, person_id): """确保返回浮点数,转换失败返回0.0""" if isinstance(value, float): return value From 06ef607e775625d987ba789eb4d07190c82cfb2c Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Thu, 3 Apr 2025 21:30:53 +0800 Subject: [PATCH 11/13] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8Dwilling?= =?UTF-8?q?=E5=92=8C=E8=A1=A8=E6=83=85=E5=8C=85=E4=B8=8D=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 2 ++ src/plugins/chat/emoji_manager.py | 4 +++- src/plugins/chat_module/think_flow_chat/think_flow_chat.py | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main.py b/src/main.py index af2896c79..e3bbf38d1 100644 --- a/src/main.py +++ b/src/main.py @@ -50,6 +50,7 @@ class MainSystem: # 初始化表情管理器 emoji_manager.initialize() + logger.success("表情包管理器初始化成功") # 启动情绪管理器 self.mood_manager.start_mood_update(update_interval=global_config.mood_update_interval) @@ -106,6 +107,7 @@ class MainSystem: self.print_mood_task(), self.remove_recalled_message_task(), emoji_manager.start_periodic_check(), + emoji_manager.start_periodic_register(), self.app.run(), ] await asyncio.gather(*tasks) diff --git a/src/plugins/chat/emoji_manager.py b/src/plugins/chat/emoji_manager.py index 18a54b1ec..279dfb464 100644 --- a/src/plugins/chat/emoji_manager.py +++ b/src/plugins/chat/emoji_manager.py @@ -38,6 +38,8 @@ class EmojiManager: self.llm_emotion_judge = LLM_request( model=global_config.llm_emotion_judge, max_tokens=600, temperature=0.8, request_type="emoji" ) # 更高的温度,更少的token(后续可以根据情绪来调整温度) + + logger.info("启动表情包管理器") def _ensure_emoji_dir(self): """确保表情存储目录存在""" @@ -338,7 +340,7 @@ class EmojiManager: except Exception: logger.exception("[错误] 扫描表情包失败") - async def _periodic_scan(self): + async def start_periodic_register(self): """定期扫描新表情包""" while True: logger.info("[扫描] 开始扫描新表情包...") diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 8197af0b1..9ed08971d 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -191,7 +191,9 @@ class ThinkFlowChat: # 计算回复意愿 current_willing_old = willing_manager.get_willing(chat_stream=chat) current_willing_new = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4 - current_willing = (current_willing_old + current_willing_new) / 2 + # current_willing = (current_willing_old + current_willing_new) / 2 + # 有点bug + current_willing = current_willing_old willing_manager.set_willing(chat.stream_id, current_willing) From 10a72b489e295a5b5ec84881cf74d64f9ba07959 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Thu, 3 Apr 2025 22:21:32 +0800 Subject: [PATCH 12/13] =?UTF-8?q?fix=EF=BC=9A=E5=B0=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_sender.py | 2 ++ .../chat_module/think_flow_chat/think_flow_chat.py | 6 ++++++ .../think_flow_chat/think_flow_prompt_builder.py | 1 + src/plugins/moods/moods.py | 8 +++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/plugins/chat/message_sender.py b/src/plugins/chat/message_sender.py index a12f7320b..daba61552 100644 --- a/src/plugins/chat/message_sender.py +++ b/src/plugins/chat/message_sender.py @@ -67,6 +67,8 @@ class Message_Sender: try: end_point = global_config.api_urls.get(message.message_info.platform, None) if end_point: + # logger.info(f"发送消息到{end_point}") + # logger.info(message_json) await global_api.send_message(end_point, message_json) else: raise ValueError(f"未找到平台:{message.message_info.platform} 的url配置,请检查配置文件") diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 9ed08971d..7bf202b50 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -102,9 +102,13 @@ class ThinkFlowChat: """处理表情包""" if random() < global_config.emoji_chance: emoji_raw = await emoji_manager.get_emoji_for_text(response) + # print("11111111111111") + # logger.info(emoji_raw) if emoji_raw: emoji_path, description = emoji_raw emoji_cq = image_path_to_base64(emoji_path) + + # logger.info(emoji_cq) thinking_time_point = round(message.message_info.time, 2) @@ -123,6 +127,8 @@ class ThinkFlowChat: is_head=False, is_emoji=True, ) + + # logger.info("22222222222222") message_manager.add_message(bot_message) async def _update_using_response(self, message, response_set): diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py index cca3f0049..3cd6096e7 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py @@ -118,6 +118,7 @@ class PromptBuilder: logger.info("开始构建prompt") prompt = f""" + {relation_prompt_all}\n {chat_target} {chat_talking_prompt} 你刚刚脑子里在想: diff --git a/src/plugins/moods/moods.py b/src/plugins/moods/moods.py index 39e13b937..98fd61952 100644 --- a/src/plugins/moods/moods.py +++ b/src/plugins/moods/moods.py @@ -229,9 +229,13 @@ class MoodManager: :param intensity: 情绪强度(0.0-1.0) """ if emotion not in self.emotion_map: + logger.debug(f"[情绪更新] 未知情绪词: {emotion}") return valence_change, arousal_change = self.emotion_map[emotion] + old_valence = self.current_mood.valence + old_arousal = self.current_mood.arousal + old_mood = self.current_mood.text valence_change *= relationship_manager.gain_coefficient[relationship_manager.positive_feedback_value] @@ -246,6 +250,8 @@ class MoodManager: # 限制范围 self.current_mood.valence = max(-1.0, min(1.0, self.current_mood.valence)) self.current_mood.arousal = max(0.0, min(1.0, self.current_mood.arousal)) - + self._update_mood_text() + logger.info(f"[情绪变化] {emotion}(强度:{intensity:.2f}) | 愉悦度:{old_valence:.2f}->{self.current_mood.valence:.2f}, 唤醒度:{old_arousal:.2f}->{self.current_mood.arousal:.2f} | 心情:{old_mood}->{self.current_mood.text}") + From 62926d484c55bf504286b71cdd0e3cced3ee5309 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Thu, 3 Apr 2025 22:21:47 +0800 Subject: [PATCH 13/13] Update think_flow_chat.py --- src/plugins/chat_module/think_flow_chat/think_flow_chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 7bf202b50..87ea1575a 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -196,7 +196,7 @@ class ThinkFlowChat: # 计算回复意愿 current_willing_old = willing_manager.get_willing(chat_stream=chat) - current_willing_new = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4 + # current_willing_new = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4 # current_willing = (current_willing_old + current_willing_new) / 2 # 有点bug current_willing = current_willing_old