diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index e7b28f635..b76df2f6d 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -31,7 +31,7 @@ from src.chat.express.expression_selector import expression_selector from src.chat.memory_system.memory_activator import MemoryActivator from src.chat.memory_system.vector_instant_memory import VectorInstantMemoryV2 from src.mood.mood_manager import mood_manager -from src.person_info.person_info import Person, is_person_known +from src.person_info.person_info import get_person_info_manager from src.plugin_system.base.component_types import ActionInfo, EventType from src.plugin_system.apis import llm_api @@ -1565,8 +1565,6 @@ class DefaultReplyer: if not global_config.relationship.enable_relationship: return "" - relationship_fetcher = relationship_fetcher_manager.get_fetcher(self.chat_stream.stream_id) - # 获取用户ID person_info_manager = get_person_info_manager() person_id = await person_info_manager.get_person_id_by_person_name(sender) @@ -1574,7 +1572,48 @@ class DefaultReplyer: logger.warning(f"未找到用户 {sender} 的ID,跳过信息提取") return f"你完全不认识{sender},不理解ta的相关信息。" - return await relationship_fetcher.build_relation_info(person_id, points_num=5) + # 使用AFC关系追踪器获取关系信息 + try: + from src.chat.affinity_flow.relationship_integration import get_relationship_tracker + + relationship_tracker = get_relationship_tracker() + if relationship_tracker: + # 获取用户信息以获取真实的user_id + user_info = await person_info_manager.get_values(person_id, ["user_id", "platform"]) + user_id = user_info.get("user_id", "unknown") + + # 从数据库获取关系数据 + relationship_data = relationship_tracker._get_user_relationship_from_db(user_id) + if relationship_data: + relationship_text = relationship_data.get("relationship_text", "") + relationship_score = relationship_data.get("relationship_score", 0.3) + + # 构建丰富的关系信息描述 + if relationship_text: + # 转换关系分数为描述性文本 + if relationship_score >= 0.8: + relationship_level = "非常亲密的朋友" + elif relationship_score >= 0.6: + relationship_level = "好朋友" + elif relationship_score >= 0.4: + relationship_level = "普通朋友" + elif relationship_score >= 0.2: + relationship_level = "认识的人" + else: + relationship_level = "陌生人" + + return f"你与{sender}的关系:{relationship_level}(关系分:{relationship_score:.2f}/1.0)。{relationship_text}" + else: + return f"你与{sender}是初次见面,关系分:{relationship_score:.2f}/1.0。" + else: + return f"你完全不认识{sender},这是第一次互动。" + else: + logger.warning("AFC关系追踪器未初始化,使用默认关系信息") + return f"你与{sender}是普通朋友关系。" + + except Exception as e: + logger.error(f"获取AFC关系信息失败: {e}") + return f"你与{sender}是普通朋友关系。" def weighted_sample_no_replacement(items, weights, k) -> list: diff --git a/src/person_info/relationship_fetcher.py b/src/person_info/relationship_fetcher.py index 4b25f6b14..8a502a73b 100644 --- a/src/person_info/relationship_fetcher.py +++ b/src/person_info/relationship_fetcher.py @@ -94,84 +94,133 @@ class RelationshipFetcher: if not self.info_fetched_cache[person_id]: del self.info_fetched_cache[person_id] - async def build_relation_info(self, person_id, points_num=3): + async def build_relation_info(self, person_id, points_num=5): + """构建详细的人物关系信息,包含从数据库中查询的丰富关系描述""" # 清理过期的信息缓存 self._cleanup_expired_cache() person_info_manager = get_person_info_manager() - person_info = await person_info_manager.get_values( - person_id, ["person_name", "short_impression", "nickname", "platform", "points"] - ) - person_name = person_info.get("person_name") - short_impression = person_info.get("short_impression") - nickname_str = person_info.get("nickname") - platform = person_info.get("platform") + person_name = await person_info_manager.get_value(person_id, "person_name") + short_impression = await person_info_manager.get_value(person_id, "short_impression") + full_impression = await person_info_manager.get_value(person_id, "impression") + attitude = await person_info_manager.get_value(person_id, "attitude") or 50 - if person_name == nickname_str and not short_impression: - return "" + nickname_str = await person_info_manager.get_value(person_id, "nickname") + platform = await person_info_manager.get_value(person_id, "platform") + know_times = await person_info_manager.get_value(person_id, "know_times") or 0 + know_since = await person_info_manager.get_value(person_id, "know_since") + last_know = await person_info_manager.get_value(person_id, "last_know") - current_points = person_info.get("points") - if isinstance(current_points, str): - current_points = orjson.loads(current_points) + # 如果用户没有基本信息,返回默认描述 + if person_name == nickname_str and not short_impression and not full_impression: + return f"你完全不认识{person_name},这是你们第一次交流。" + + # 获取用户特征点 + current_points = await person_info_manager.get_value(person_id, "points") or [] + forgotten_points = await person_info_manager.get_value(person_id, "forgotten_points") or [] + + # 按时间排序并选择最有代表性的特征点 + all_points = current_points + forgotten_points + if all_points: + # 按权重和时效性综合排序 + all_points.sort(key=lambda x: (float(x[1]) if len(x) > 1 else 0, float(x[2]) if len(x) > 2 else 0), reverse=True) + selected_points = all_points[:points_num] + points_text = "\n".join([f"- {point[0]}({point[2]})" for point in selected_points if len(point) > 2]) else: - current_points = current_points or [] + points_text = "" - # 按时间排序forgotten_points - current_points.sort(key=lambda x: x[2]) - # 按权重加权随机抽取最多3个不重复的points,point[1]的值在1-10之间,权重越高被抽到概率越大 - if len(current_points) > points_num: - # point[1] 取值范围1-10,直接作为权重 - weights = [max(1, min(10, int(point[1]))) for point in current_points] - # 使用加权采样不放回,保证不重复 - indices = list(range(len(current_points))) - points = [] - for _ in range(points_num): - if not indices: - break - sub_weights = [weights[i] for i in indices] - chosen_idx = random.choices(indices, weights=sub_weights, k=1)[0] - points.append(current_points[chosen_idx]) - indices.remove(chosen_idx) + # 构建详细的关系描述 + relation_parts = [] + + # 1. 基本信息 + if nickname_str and person_name != nickname_str: + relation_parts.append(f"用户{person_name}在{platform}平台的昵称是{nickname_str}") + + # 2. 认识时间和频率 + if know_since: + from datetime import datetime + know_time = datetime.fromtimestamp(know_since).strftime('%Y年%m月%d日') + relation_parts.append(f"你从{know_time}开始认识{person_name}") + + if know_times > 0: + relation_parts.append(f"你们已经交流过{int(know_times)}次") + + if last_know: + from datetime import datetime + last_time = datetime.fromtimestamp(last_know).strftime('%m月%d日') + relation_parts.append(f"最近一次交流是在{last_time}") + + # 3. 态度和印象 + attitude_desc = self._get_attitude_description(attitude) + relation_parts.append(f"你对{person_name}的态度是{attitude_desc}") + + if short_impression: + relation_parts.append(f"你对ta的总体印象:{short_impression}") + + if full_impression: + relation_parts.append(f"更详细的了解:{full_impression}") + + # 4. 特征点和记忆 + if points_text: + relation_parts.append(f"你记得关于{person_name}的一些事情:\n{points_text}") + + # 5. 从UserRelationships表获取额外关系信息 + try: + from src.common.database.sqlalchemy_database_api import db_query + from src.common.database.sqlalchemy_models import UserRelationships + + # 查询用户关系数据 + relationships = await db_query( + UserRelationships, + filters=[UserRelationships.user_id == str(person_info_manager.get_value_sync(person_id, "user_id"))], + limit=1 + ) + + if relationships: + rel_data = relationships[0] + if rel_data.relationship_text: + relation_parts.append(f"关系记录:{rel_data.relationship_text}") + if rel_data.relationship_score: + score_desc = self._get_relationship_score_description(rel_data.relationship_score) + relation_parts.append(f"关系亲密程度:{score_desc}") + + except Exception as e: + logger.debug(f"查询UserRelationships表失败: {e}") + + # 构建最终的关系信息字符串 + if relation_parts: + relation_info = f"关于{person_name},你知道以下信息:\n" + "\n".join([f"• {part}" for part in relation_parts]) else: - points = current_points - - # 构建points文本 - points_text = "\n".join([f"{point[2]}:{point[0]}" for point in points]) - - nickname_str = "" - if person_name != nickname_str: - nickname_str = f"(ta在{platform}上的昵称是{nickname_str})" - - relation_info = "" - - if short_impression and relation_info: - if points_text: - relation_info = f"你对{person_name}的印象是{nickname_str}:{short_impression}。具体来说:{relation_info}。你还记得ta最近做的事:{points_text}" - else: - relation_info = ( - f"你对{person_name}的印象是{nickname_str}:{short_impression}。具体来说:{relation_info}" - ) - elif short_impression: - if points_text: - relation_info = ( - f"你对{person_name}的印象是{nickname_str}:{short_impression}。你还记得ta最近做的事:{points_text}" - ) - else: - relation_info = f"你对{person_name}的印象是{nickname_str}:{short_impression}" - elif relation_info: - if points_text: - relation_info = ( - f"你对{person_name}的了解{nickname_str}:{relation_info}。你还记得ta最近做的事:{points_text}" - ) - else: - relation_info = f"你对{person_name}的了解{nickname_str}:{relation_info}" - elif points_text: - relation_info = f"你记得{person_name}{nickname_str}最近做的事:{points_text}" - else: - relation_info = "" + relation_info = f"你对{person_name}了解不多,这是比较初步的交流。" return relation_info + def _get_attitude_description(self, attitude: int) -> str: + """根据态度分数返回描述性文字""" + if attitude >= 80: + return "非常喜欢和欣赏" + elif attitude >= 60: + return "比较有好感" + elif attitude >= 40: + return "中立态度" + elif attitude >= 20: + return "有些反感" + else: + return "非常厌恶" + + def _get_relationship_score_description(self, score: float) -> str: + """根据关系分数返回描述性文字""" + if score >= 0.8: + return "非常亲密的好友" + elif score >= 0.6: + return "关系不错的朋友" + elif score >= 0.4: + return "普通熟人" + elif score >= 0.2: + return "认识但不熟悉" + else: + return "陌生人" + async def _build_fetch_query(self, person_id, target_message, chat_history): nickname_str = ",".join(global_config.bot.alias_names) name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"