diff --git a/src/chat/affinity_flow/afc_manager.py b/src/chat/affinity_flow/afc_manager.py index b67ae6939..c96873089 100644 --- a/src/chat/affinity_flow/afc_manager.py +++ b/src/chat/affinity_flow/afc_manager.py @@ -9,6 +9,7 @@ from typing import Dict, Optional, List from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.planner import ActionPlanner from src.chat.affinity_flow.chatter import AffinityFlowChatter +from src.common.data_models.message_manager_data_model import StreamContext from src.common.logger import get_logger logger = get_logger("afc_manager") @@ -49,7 +50,7 @@ class AFCManager: return self.affinity_flow_chatters[stream_id] - async def process_stream_context(self, stream_id: str, context) -> Dict[str, any]: + async def process_stream_context(self, stream_id: str, context: StreamContext) -> Dict[str, any]: """处理StreamContext对象""" try: # 获取或创建聊天处理器 diff --git a/src/chat/affinity_flow/chatter.py b/src/chat/affinity_flow/chatter.py index a613a143e..7e5f9e6f1 100644 --- a/src/chat/affinity_flow/chatter.py +++ b/src/chat/affinity_flow/chatter.py @@ -9,6 +9,7 @@ from typing import Dict from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.planner import ActionPlanner +from src.common.data_models.message_manager_data_model import StreamContext from src.plugin_system.base.component_types import ChatMode from src.common.logger import get_logger @@ -42,7 +43,7 @@ class AffinityFlowChatter: } self.last_activity_time = time.time() - async def process_stream_context(self, context) -> Dict[str, any]: + async def process_stream_context(self, context: StreamContext) -> Dict[str, any]: """ 处理StreamContext对象 @@ -53,27 +54,18 @@ class AffinityFlowChatter: 处理结果字典 """ try: - # 获取未读消息和历史消息 unread_messages = context.get_unread_messages() - history_messages = context.get_history_messages() - - # 准备消息数据 - message_data = { - "unread_messages": unread_messages, - "history_messages": history_messages - } # 使用增强版规划器处理消息 actions, target_message = await self.planner.plan( mode=ChatMode.FOCUS, - message_data=message_data + context=context ) self.stats["plans_created"] += 1 # 执行动作(如果规划器返回了动作) execution_result = {"executed_count": len(actions) if actions else 0} if actions: - # 这里可以添加额外的动作执行逻辑 logger.debug(f"聊天流 {self.stream_id} 生成了 {len(actions)} 个动作") # 更新统计 diff --git a/src/chat/affinity_flow/relationship_tracker.py b/src/chat/affinity_flow/relationship_tracker.py index 55dfa7d62..8d5af05d0 100644 --- a/src/chat/affinity_flow/relationship_tracker.py +++ b/src/chat/affinity_flow/relationship_tracker.py @@ -114,20 +114,49 @@ class UserRelationshipTracker: async def _update_user_relationship(self, interaction: Dict) -> Optional[Dict]: """更新单个用户的关系""" try: + # 获取bot人设信息 + from src.individuality.individuality import Individuality + individuality = Individuality() + bot_personality = await individuality.get_personality_block() + prompt = f""" -分析以下用户交互,更新用户关系: +你现在是一个有着特定性格和身份的AI助手。你的人设是:{bot_personality} + +请以你独特的性格视角,严格按现实逻辑分析以下用户交互,更新用户关系: 用户ID: {interaction["user_id"]} 用户名: {interaction["user_name"]} 用户消息: {interaction["user_message"]} -Bot回复: {interaction["bot_reply"]} +你的回复: {interaction["bot_reply"]} 当前关系分: {interaction["current_relationship_score"]} +【重要】关系分数档次定义: +- 0.0-0.2:陌生人/初次认识 - 仅礼貌性交流 +- 0.2-0.4:普通网友 - 有基本互动但不熟悉 +- 0.4-0.6:熟悉网友 - 经常交流,有一定了解 +- 0.6-0.8:朋友 - 可以分享心情,互相关心 +- 0.8-1.0:好朋友/知己 - 深度信任,亲密无间 + +【严格要求】: +1. 加分必须符合现实关系发展逻辑 - 不能因为对方态度好就盲目加分到不符合当前关系档次的分数 +2. 关系提升需要足够的互动积累和时间验证 +3. 即使是朋友关系,单次互动加分通常不超过0.05-0.1 +4. 关系描述要详细具体,包括: + - 用户性格特点观察 + - 印象深刻的互动记忆 + - 你们关系的具体状态描述 + +根据你的人设性格,思考: +1. 以你的性格,你会如何看待这次互动? +2. 用户的行为是否符合你性格的喜好? +3. 这次互动是否真的让你们的关系提升了一个档次?为什么? +4. 有什么特别值得记住的互动细节? + 请以JSON格式返回更新结果: {{ - "new_relationship_score": 0.0~1.0的数值, - "reasoning": "更新理由", - "interaction_summary": "交互总结" + "new_relationship_score": 0.0~1.0的数值(必须符合现实逻辑), + "reasoning": "从你的性格角度说明更新理由,重点说明是否符合现实关系发展逻辑", + "interaction_summary": "基于你性格的交互总结,包含印象深刻的互动记忆" }} """ @@ -470,36 +499,59 @@ Bot回复: {interaction["bot_reply"]} # 构建分析提示 user_reactions_text = "\n".join([f"- {msg.processed_plain_text}" for msg in user_reactions]) + # 获取bot人设信息 + from src.individuality.individuality import Individuality + individuality = Individuality() + bot_personality = await individuality.get_personality_block() + prompt = f""" -分析以下用户交互,更新用户关系印象和分数: +你现在是一个有着特定性格和身份的AI助手。你的人设是:{bot_personality} + +请以你独特的性格视角,严格按现实逻辑分析以下用户交互,更新用户关系印象和分数: 用户信息: - 用户ID: {user_id} - 用户名: {user_name} -上次Bot回复: {last_bot_reply.processed_plain_text} +你上次的回复: {last_bot_reply.processed_plain_text} 用户反应消息: {user_reactions_text} -当前Bot回复: {current_reply} +你当前的回复: {current_reply} 当前关系印象: {current_text} 当前关系分数: {current_score:.3f} -请根据用户的反应和对话内容,分析用户性格特点、与Bot的互动模式,然后更新关系印象和分数。 +【重要】关系分数档次定义: +- 0.0-0.2:陌生人/初次认识 - 仅礼貌性交流 +- 0.2-0.4:普通网友 - 有基本互动但不熟悉 +- 0.4-0.6:熟悉网友 - 经常交流,有一定了解 +- 0.6-0.8:朋友 - 可以分享心情,互相关心 +- 0.8-1.0:好朋友/知己 - 深度信任,亲密无间 -分析要点: -1. 用户的情绪态度(积极/消极/中性) -2. 用户对Bot的兴趣程度 -3. 用户的交流风格(主动/被动/友好/正式等) -4. 互动的质量和深度 +【严格要求】: +1. 加分必须符合现实关系发展逻辑 - 不能因为用户反应好就盲目加分 +2. 关系提升需要足够的互动积累和时间验证,单次互动加分通常不超过0.05-0.1 +3. 必须考虑当前关系档次,不能跳跃式提升(比如从0.3直接到0.7) +4. 关系印象描述要详细具体(100-200字),包括: + - 用户性格特点和交流风格观察 + - 印象深刻的互动记忆和对话片段 + - 你们关系的具体状态描述和发展阶段 + - 根据你的性格,你对用户的真实感受 + +性格视角深度分析: +1. 以你的性格特点,用户这次的反应给你什么感受? +2. 用户的情绪和行为符合你性格的喜好吗?具体哪些方面? +3. 从现实角度看,这次互动是否足以让关系提升到下一个档次?为什么? +4. 有什么特别值得记住的互动细节或对话内容? +5. 基于你们的互动历史,用户给你留下了哪些深刻印象? 请以JSON格式返回更新结果: {{ - "relationship_text": "更新的关系印象描述(50字以内)", - "relationship_score": 0.0~1.0的新分数, - "analysis_reasoning": "分析理由说明", + "relationship_text": "详细的关系印象描述(100-200字),包含用户性格观察、印象深刻记忆、关系状态描述", + "relationship_score": 0.0~1.0的新分数(必须严格符合现实逻辑), + "analysis_reasoning": "从你性格角度的深度分析,重点说明分数调整的现实合理性", "interaction_quality": "high/medium/low" }} """ diff --git a/src/chat/message_manager/message_manager.py b/src/chat/message_manager/message_manager.py index 503d92c03..2f12112ca 100644 --- a/src/chat/message_manager/message_manager.py +++ b/src/chat/message_manager/message_manager.py @@ -134,9 +134,7 @@ class MessageManager: self._clear_all_unread_messages(context) except Exception as e: - # 发生异常时,清除所有未读消息,防止意外关闭等导致消息一直未读 logger.error(f"处理聊天流 {stream_id} 时发生异常,将清除所有未读消息: {e}") - self._clear_all_unread_messages(context) raise logger.debug(f"聊天流 {stream_id} 消息处理完成") diff --git a/src/chat/planner_actions/plan_executor.py b/src/chat/planner_actions/plan_executor.py index b325c882d..009250ccd 100644 --- a/src/chat/planner_actions/plan_executor.py +++ b/src/chat/planner_actions/plan_executor.py @@ -126,7 +126,7 @@ class PlanExecutor: try: logger.info(f"执行回复动作: {action_info.action_type}, 原因: {action_info.reasoning}") - if action_info.action_message.get("user_id", "") == str(global_config.bot.qq_account): + if action_info.action_message.user_info.user_id == str(global_config.bot.qq_account): logger.warning("尝试回复自己,跳过此动作以防止死循环。") return { "action_type": action_info.action_type, diff --git a/src/chat/planner_actions/plan_filter.py b/src/chat/planner_actions/plan_filter.py index 2c0802116..765f7292e 100644 --- a/src/chat/planner_actions/plan_filter.py +++ b/src/chat/planner_actions/plan_filter.py @@ -263,9 +263,6 @@ class PlanFilter: # 获取聊天流的上下文 stream_context = message_manager.stream_contexts.get(plan.chat_id) - if not stream_context: - # 如果没有找到对应的上下文,使用兼容性处理 - return await self._fallback_build_history_blocks(plan) # 获取真正的已读和未读消息 read_messages = stream_context.history_messages # 已读消息存储在history_messages中 diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index 0da687f2f..f39ee67a0 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -13,6 +13,7 @@ from src.chat.planner_actions.plan_generator import PlanGenerator from src.chat.affinity_flow.interest_scoring import InterestScoringSystem from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker from src.common.data_models.info_data_model import Plan +from src.common.data_models.message_manager_data_model import StreamContext from src.common.logger import get_logger from src.config.config import global_config from src.plugin_system.base.component_types import ChatMode @@ -84,16 +85,14 @@ class ActionPlanner: } async def plan( - self, mode: ChatMode = ChatMode.FOCUS, message_data: dict = None + self, mode: ChatMode = ChatMode.FOCUS, context: StreamContext = None ) -> Tuple[List[Dict], Optional[Dict]]: """ 执行完整的增强版规划流程。 Args: mode (ChatMode): 当前的聊天模式,默认为 FOCUS。 - message_data (dict): 消息数据字典,包含: - - unread_messages: 未读消息列表 - - history_messages: 历史消息列表(可选) + context (StreamContext): 包含聊天流消息的上下文对象。 Returns: Tuple[List[Dict], Optional[Dict]]: 一个元组,包含: @@ -101,11 +100,9 @@ class ActionPlanner: - final_target_message_dict (Optional[Dict]): 最终的目标消息(字典格式)。 """ try: - # 提取未读消息用于兴趣度计算 - unread_messages = message_data.get("unread_messages", []) if message_data else [] self.planner_stats["total_plans"] += 1 - return await self._enhanced_plan_flow(mode, unread_messages or []) + return await self._enhanced_plan_flow(mode, context) except Exception as e: logger.error(f"规划流程出错: {e}") @@ -113,13 +110,14 @@ class ActionPlanner: return [], None async def _enhanced_plan_flow( - self, mode: ChatMode, unread_messages: List[Dict] + self, mode: ChatMode, context: StreamContext ) -> Tuple[List[Dict], Optional[Dict]]: """执行增强版规划流程""" try: # 1. 生成初始 Plan initial_plan = await self.generator.generate(mode) + unread_messages = context.get_unread_messages() if context else [] # 2. 兴趣度评分 - 只对未读消息进行评分 if unread_messages: bot_nickname = global_config.bot.nickname @@ -135,8 +133,8 @@ class ActionPlanner: logger.info(f"消息兴趣度不足({latest_score.total_score:.2f}),移除reply动作") reply_not_available = True - base_threshold = self.interest_scoring.reply_threshold - # 检查兴趣度是否达到阈值的0.8 + # base_threshold = self.interest_scoring.reply_threshold + # 检查兴趣度是否达到非回复动作阈值 non_reply_action_interest_threshold = global_config.affinity_flow.non_reply_action_interest_threshold if score < non_reply_action_interest_threshold: logger.info(f"❌ 兴趣度不足非回复动作阈值: {score:.3f} < {non_reply_action_interest_threshold:.3f},直接返回no_action") diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index 418295a21..e837964ca 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -987,8 +987,9 @@ class DefaultReplyer: if person_name is None: # 尝试从reply_message获取用户名 fallback_name = reply_message.get("user_nickname") or reply_message.get("user_id", "未知用户") - logger.warning(f"无法获取person_name,使用fallback: {fallback_name}") + logger.warning(f"未知用户,将存储用户信息:{fallback_name}") person_name = str(fallback_name) + person_info_manager.set_value(person_id, "person_name", fallback_name) # 检查是否是bot自己的名字,如果是则替换为"(你)" bot_user_id = str(global_config.bot.qq_account) diff --git a/src/person_info/person_info.py b/src/person_info/person_info.py index 2f89c43ff..e0c582b10 100644 --- a/src/person_info/person_info.py +++ b/src/person_info/person_info.py @@ -93,10 +93,50 @@ class PersonInfoManager: if "-" in platform: platform = platform.split("-")[1] - + # 在此处打一个补丁,如果platform为qq,尝试生成id后检查是否存在,如果不存在,则将平台换为napcat后再次检查,如果存在,则更新原id为platform为qq的id components = [platform, str(user_id)] key = "_".join(components) - return hashlib.md5(key.encode()).hexdigest() + + # 如果不是 qq 平台,直接返回计算的 id + if platform != "qq": + return hashlib.md5(key.encode()).hexdigest() + + qq_id = hashlib.md5(key.encode()).hexdigest() + # 对于 qq 平台,先检查该 person_id 是否已存在;如果存在直接返回 + def _db_check_and_migrate_sync(p_id: str, raw_user_id: str): + try: + with get_db_session() as session: + # 检查 qq_id 是否存在 + existing_qq = session.execute(select(PersonInfo).where(PersonInfo.person_id == p_id)).scalar() + if existing_qq: + return p_id + + # 如果 qq_id 不存在,尝试使用 napcat 作为平台生成对应 id 并检查 + nap_components = ["napcat", str(raw_user_id)] + nap_key = "_".join(nap_components) + nap_id = hashlib.md5(nap_key.encode()).hexdigest() + + existing_nap = session.execute(select(PersonInfo).where(PersonInfo.person_id == nap_id)).scalar() + if not existing_nap: + # napcat 也不存在,返回 qq_id(未命中) + return p_id + + # napcat 存在,迁移该记录:更新 person_id 与 platform -> qq + try: + # 更新现有 napcat 记录 + existing_nap.person_id = p_id + existing_nap.platform = "qq" + existing_nap.user_id = str(raw_user_id) + session.commit() + return p_id + except Exception: + session.rollback() + return p_id + except Exception as e: + logger.error(f"检查/迁移 napcat->qq 时出错: {e}") + return p_id + + return _db_check_and_migrate_sync(qq_id, user_id) async def is_person_known(self, platform: str, user_id: int): """判断是否认识某人""" diff --git a/src/plugins/built_in/napcat_adapter_plugin/src/mmc_com_layer.py b/src/plugins/built_in/napcat_adapter_plugin/src/mmc_com_layer.py index c735d63cf..655fff64c 100644 --- a/src/plugins/built_in/napcat_adapter_plugin/src/mmc_com_layer.py +++ b/src/plugins/built_in/napcat_adapter_plugin/src/mmc_com_layer.py @@ -11,7 +11,7 @@ router = None def create_router(plugin_config: dict): """创建路由器实例""" global router - platform_name = config_api.get_plugin_config(plugin_config, "maibot_server.platform_name", "napcat") + platform_name = config_api.get_plugin_config(plugin_config, "maibot_server.platform_name", "qq") host = config_api.get_plugin_config(plugin_config, "maibot_server.host", "localhost") port = config_api.get_plugin_config(plugin_config, "maibot_server.port", 8000)