feat(person-info): 增强人物关系信息构建功能
重构关系信息构建逻辑,从数据库查询更多维度数据生成详细关系描述: - 增加认识时间、交流频率、态度评分等基本信息 - 整合UserRelationships表的额外关系数据 - 添加态度和关系分数的描述性文字转换方法 - 优化特征点选择策略,按权重和时效性综合排序 - 提供更结构化的关系信息输出格式
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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},有人也会用这些昵称称呼你。"
|
||||
|
||||
Reference in New Issue
Block a user