diff --git a/src/chat/energy_system/energy_manager.py b/src/chat/energy_system/energy_manager.py index 1120b62cf..7cf84eda7 100644 --- a/src/chat/energy_system/energy_manager.py +++ b/src/chat/energy_system/energy_manager.py @@ -199,16 +199,16 @@ class RelationshipEnergyCalculator(EnergyCalculator): if not user_id: return 0.3 - # 使用插件内部的兴趣度评分系统获取关系分 + # 使用统一的评分API获取关系分 try: - from src.plugins.built_in.affinity_flow_chatter.interest_scoring import chatter_interest_scoring_system + from src.plugin_system.apis.scoring_api import scoring_api - relationship_score = await chatter_interest_scoring_system._calculate_relationship_score(user_id) - logger.debug(f"使用插件内部系统计算关系分: {relationship_score:.3f}") - return max(0.0, min(1.0, relationship_score)) + relationship_score = await scoring_api.get_user_relationship_score(user_id) + logger.debug(f"使用统一评分API计算关系分: {relationship_score:.3f}") + return relationship_score except Exception as e: - logger.warning(f"插件内部关系分计算失败,使用默认值: {e}") + logger.warning(f"关系分计算失败,使用默认值: {e}") return 0.3 # 默认基础分 def get_weight(self) -> float: diff --git a/src/chat/message_receive/chat_stream.py b/src/chat/message_receive/chat_stream.py index 223b50f9d..bb6fa6b99 100644 --- a/src/chat/message_receive/chat_stream.py +++ b/src/chat/message_receive/chat_stream.py @@ -405,18 +405,18 @@ class ChatStream: async def _get_user_relationship_score(self) -> float: """获取用户关系分""" - # 使用插件内部的兴趣度评分系统 + # 使用统一的评分API try: - from src.plugins.built_in.affinity_flow_chatter.interest_scoring import chatter_interest_scoring_system + from src.plugin_system.apis.scoring_api import scoring_api if self.user_info and hasattr(self.user_info, "user_id"): user_id = str(self.user_info.user_id) - relationship_score = await chatter_interest_scoring_system._calculate_relationship_score(user_id) + relationship_score = await scoring_api.get_user_relationship_score(user_id) logger.debug(f"ChatStream {self.stream_id}: 用户关系分 = {relationship_score:.3f}") - return max(0.0, min(1.0, relationship_score)) + return relationship_score except Exception as e: - logger.warning(f"ChatStream {self.stream_id}: 插件内部关系分计算失败: {e}") + logger.warning(f"ChatStream {self.stream_id}: 关系分计算失败: {e}") # 默认基础分 return 0.3 diff --git a/src/chat/message_receive/optimized_chat_stream.py b/src/chat/message_receive/optimized_chat_stream.py index d9280c61a..939c6e6ce 100644 --- a/src/chat/message_receive/optimized_chat_stream.py +++ b/src/chat/message_receive/optimized_chat_stream.py @@ -436,17 +436,17 @@ class OptimizedChatStream: async def _get_user_relationship_score(self) -> float: """获取用户关系分""" try: - from src.plugins.built_in.affinity_flow_chatter.interest_scoring import chatter_interest_scoring_system + from src.plugin_system.apis.scoring_api import scoring_api effective_user_info = self._get_effective_user_info() if effective_user_info and hasattr(effective_user_info, "user_id"): user_id = str(effective_user_info.user_id) - relationship_score = await chatter_interest_scoring_system._calculate_relationship_score(user_id) + relationship_score = await scoring_api.get_user_relationship_score(user_id) logger.debug(f"OptimizedChatStream {self.stream_id}: 用户关系分 = {relationship_score:.3f}") - return max(0.0, min(1.0, relationship_score)) + return relationship_score except Exception as e: - logger.warning(f"OptimizedChatStream {self.stream_id}: 插件内部关系分计算失败: {e}") + logger.warning(f"OptimizedChatStream {self.stream_id}: 关系分计算失败: {e}") return 0.3 diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index 5f42c0042..f4a436797 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -1676,49 +1676,42 @@ class DefaultReplyer: logger.warning(f"未找到用户 {sender} 的ID,跳过信息提取") return f"你完全不认识{sender},不理解ta的相关信息。" - # 使用AFC关系追踪器获取关系信息 + # 使用统一评分API获取关系信息 try: - # 创建关系追踪器实例 - from src.plugins.built_in.affinity_flow_chatter.interest_scoring import chatter_interest_scoring_system - from src.plugins.built_in.affinity_flow_chatter.relationship_tracker import ChatterRelationshipTracker + from src.plugin_system.apis.scoring_api import scoring_api - relationship_tracker = ChatterRelationshipTracker(chatter_interest_scoring_system) - 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") + # 获取用户信息以获取真实的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 = await 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) + # 从统一API获取关系数据 + relationship_data = await scoring_api.get_user_relationship_data(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}" + # 构建丰富的关系信息描述 + 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: - return f"你与{sender}是初次见面,关系分:{relationship_score:.2f}/1.0。" + relationship_level = "陌生人" + + return f"你与{sender}的关系:{relationship_level}(关系分:{relationship_score:.2f}/1.0)。{relationship_text}" else: - return f"你完全不认识{sender},这是第一次互动。" + return f"你与{sender}是初次见面,关系分:{relationship_score:.2f}/1.0。" else: - logger.warning("AFC关系追踪器未初始化,使用默认关系信息") - return f"你与{sender}是普通朋友关系。" + return f"你完全不认识{sender},这是第一次互动。" except Exception as e: - logger.error(f"获取AFC关系信息失败: {e}") + logger.error(f"获取关系信息失败: {e}") return f"你与{sender}是普通朋友关系。" async def _store_chat_memory_async(self, reply_to: str, reply_message: dict[str, Any] | None = None): diff --git a/src/individuality/individuality.py b/src/individuality/individuality.py index 83c24d4f6..271b2e4e7 100644 --- a/src/individuality/individuality.py +++ b/src/individuality/individuality.py @@ -84,13 +84,10 @@ class Individuality: # 组合完整的人设描述 full_personality = f"{personality_result},{identity_result}" - # 获取全局兴趣评分系统实例 - from src.plugins.built_in.affinity_flow_chatter.interest_scoring import ( - chatter_interest_scoring_system as interest_scoring_system, - ) + # 使用统一的评分API初始化智能兴趣系统 + from src.plugin_system.apis.scoring_api import scoring_api - # 初始化智能兴趣系统 - await interest_scoring_system.initialize_smart_interests( + await scoring_api.initialize_smart_interests( personality_description=full_personality, personality_id=self.bot_person_id ) diff --git a/src/plugin_system/apis/scoring_api.py b/src/plugin_system/apis/scoring_api.py new file mode 100644 index 000000000..dbb128dca --- /dev/null +++ b/src/plugin_system/apis/scoring_api.py @@ -0,0 +1,113 @@ +""" +统一评分系统API +提供系统级的关系分和兴趣管理服务,供所有插件和主项目组件使用 +""" + +from typing import Any + +from src.common.logger import get_logger +from src.plugin_system.services.interest_service import interest_service +from src.plugin_system.services.relationship_service import relationship_service + +logger = get_logger("scoring_api") + + +class ScoringAPI: + """ + 统一评分系统API - 系统级服务 + + 提供关系分和兴趣管理的统一接口,替代原有的插件依赖方式。 + 所有插件和主项目组件都应该通过此API访问评分功能。 + """ + + @staticmethod + async def get_user_relationship_score(user_id: str) -> float: + """ + 获取用户关系分 + + Args: + user_id: 用户ID + + Returns: + 关系分 (0.0 - 1.0) + """ + return await relationship_service.get_user_relationship_score(user_id) + + @staticmethod + async def get_user_relationship_data(user_id: str) -> dict: + """ + 获取用户完整关系数据 + + Args: + user_id: 用户ID + + Returns: + 包含关系分、关系文本等的字典 + """ + return await relationship_service.get_user_relationship_data(user_id) + + @staticmethod + async def update_user_relationship(user_id: str, relationship_score: float, relationship_text: str = None, user_name: str = None): + """ + 更新用户关系数据 + + Args: + user_id: 用户ID + relationship_score: 关系分 (0.0 - 1.0) + relationship_text: 关系描述文本 + user_name: 用户名称 + """ + await relationship_service.update_user_relationship(user_id, relationship_score, relationship_text, user_name) + + @staticmethod + async def initialize_smart_interests(personality_description: str, personality_id: str = "default"): + """ + 初始化智能兴趣系统 + + Args: + personality_description: 机器人性格描述 + personality_id: 性格ID + """ + await interest_service.initialize_smart_interests(personality_description, personality_id) + + @staticmethod + async def calculate_interest_match(content: str, keywords: list[str] = None): + """ + 计算内容与兴趣的匹配度 + + Args: + content: 消息内容 + keywords: 关键词列表 + + Returns: + 匹配结果 + """ + return await interest_service.calculate_interest_match(content, keywords) + + @staticmethod + def get_system_stats() -> dict[str, Any]: + """ + 获取系统统计信息 + + Returns: + 包含各子系统统计的字典 + """ + return { + "relationship_service": relationship_service.get_cache_stats(), + "interest_service": interest_service.get_interest_stats() + } + + @staticmethod + def clear_caches(user_id: str = None): + """ + 清理缓存 + + Args: + user_id: 特定用户ID,如果为None则清理所有缓存 + """ + relationship_service.clear_cache(user_id) + logger.info(f"清理缓存: {user_id if user_id else '全部'}") + + +# 创建全局API实例 - 系统级服务 +scoring_api = ScoringAPI() \ No newline at end of file diff --git a/src/plugin_system/services/interest_service.py b/src/plugin_system/services/interest_service.py new file mode 100644 index 000000000..384eacf43 --- /dev/null +++ b/src/plugin_system/services/interest_service.py @@ -0,0 +1,108 @@ +""" +兴趣系统服务 +提供独立的兴趣管理功能,不依赖任何插件 +""" + +from typing import Optional + +from src.chat.interest_system import bot_interest_manager +from src.common.logger import get_logger + +logger = get_logger("interest_service") + + +class InterestService: + """兴趣系统服务 - 独立于插件的兴趣管理""" + + def __init__(self): + self.is_initialized = bot_interest_manager.is_initialized + + async def initialize_smart_interests(self, personality_description: str, personality_id: str = "default"): + """ + 初始化智能兴趣系统 + + Args: + personality_description: 机器人性格描述 + personality_id: 性格ID + """ + try: + logger.info("开始初始化智能兴趣系统...") + logger.info(f"人设ID: {personality_id}, 描述长度: {len(personality_description)}") + + await bot_interest_manager.initialize(personality_description, personality_id) + self.is_initialized = True + logger.info("智能兴趣系统初始化完成。") + + # 显示初始化后的统计信息 + stats = bot_interest_manager.get_interest_stats() + logger.info(f"兴趣系统统计: {stats}") + + except Exception as e: + logger.error(f"初始化智能兴趣系统失败: {e}") + self.is_initialized = False + + async def calculate_interest_match(self, content: str, keywords: Optional[list[str]] = None): + """ + 计算内容与兴趣的匹配度 + + Args: + content: 消息内容 + keywords: 关键词列表 + + Returns: + 匹配结果 + """ + if not self.is_initialized: + logger.warning("兴趣系统未初始化,无法计算匹配度") + return None + + try: + if not keywords: + # 如果没有关键词,尝试从内容提取 + keywords = self._extract_keywords_from_content(content) + + return await bot_interest_manager.calculate_interest_match(content, keywords) + except Exception as e: + logger.error(f"计算兴趣匹配度失败: {e}") + return None + + def _extract_keywords_from_content(self, content: str) -> list[str]: + """从内容中提取关键词""" + import re + + # 清理文本 + content = re.sub(r"[^\w\s\u4e00-\u9fff]", " ", content) # 保留中文、英文、数字 + words = content.split() + + # 过滤和关键词提取 + keywords = [] + for word in words: + word = word.strip() + if ( + len(word) >= 2 # 至少2个字符 + and word.isalnum() # 字母数字 + and not word.isdigit() + ): # 不是纯数字 + keywords.append(word.lower()) + + # 去重并限制数量 + unique_keywords = list(set(keywords)) + return unique_keywords[:10] # 返回前10个唯一关键词 + + def get_interest_stats(self) -> dict: + """获取兴趣系统统计信息""" + if not self.is_initialized: + return {"initialized": False} + + try: + return { + "initialized": True, + **bot_interest_manager.get_interest_stats() + } + except Exception as e: + logger.error(f"获取兴趣系统统计失败: {e}") + return {"initialized": True, "error": str(e)} + + +# 创建全局实例 +interest_service = InterestService() \ No newline at end of file diff --git a/src/plugin_system/services/relationship_service.py b/src/plugin_system/services/relationship_service.py new file mode 100644 index 000000000..c50ef4276 --- /dev/null +++ b/src/plugin_system/services/relationship_service.py @@ -0,0 +1,232 @@ +""" +用户关系分服务 +提供独立的关系分获取和管理功能,不依赖任何插件 +""" + +import time +from typing import Optional + +from src.common.database.sqlalchemy_models import UserRelationships, get_db_session +from src.common.logger import get_logger +from src.config.config import global_config + +logger = get_logger("relationship_service") + + +class RelationshipService: + """用户关系分服务 - 独立于插件的数据库直接访问层""" + + def __init__(self): + self._cache: dict[str, dict] = {} # user_id -> {score, text, last_updated} + self._cache_ttl = 300 # 缓存5分钟 + + async def get_user_relationship_score(self, user_id: str) -> float: + """ + 获取用户关系分 + + Args: + user_id: 用户ID + + Returns: + 关系分 (0.0 - 1.0) + """ + try: + # 先检查缓存 + cached_data = self._get_from_cache(user_id) + if cached_data is not None: + return cached_data["score"] + + # 从数据库获取 + relationship_data = await self._fetch_from_database(user_id) + if relationship_data: + score = relationship_data.relationship_score + # 更新缓存 + self._update_cache(user_id, score, relationship_data.relationship_text) + logger.debug(f"从数据库获取用户关系分: {user_id} -> {score:.3f}") + return max(0.0, min(1.0, score)) + else: + # 用户不存在,返回默认分数并创建记录 + default_score = global_config.affinity_flow.base_relationship_score + await self._create_default_relationship(user_id) + self._update_cache(user_id, default_score, "新用户") + logger.debug(f"创建默认关系分: {user_id} -> {default_score:.3f}") + return default_score + + except Exception as e: + logger.error(f"获取用户关系分失败: {user_id}, 错误: {e}") + return global_config.affinity_flow.base_relationship_score + + async def get_user_relationship_data(self, user_id: str) -> dict: + """ + 获取用户完整关系数据 + + Args: + user_id: 用户ID + + Returns: + 包含关系分、关系文本等的字典 + """ + try: + # 先检查缓存 + cached_data = self._get_from_cache(user_id) + if cached_data is not None: + return { + "relationship_score": cached_data["score"], + "relationship_text": cached_data["text"], + "last_updated": cached_data["last_updated"] + } + + # 从数据库获取 + relationship_data = await self._fetch_from_database(user_id) + if relationship_data: + result = { + "relationship_score": relationship_data.relationship_score, + "relationship_text": relationship_data.relationship_text or "", + "last_updated": relationship_data.last_updated, + "user_name": relationship_data.user_name or "" + } + # 更新缓存 + self._update_cache(user_id, result["relationship_score"], result["relationship_text"]) + return result + else: + # 创建默认记录 + default_score = global_config.affinity_flow.base_relationship_score + await self._create_default_relationship(user_id) + default_result = { + "relationship_score": default_score, + "relationship_text": "新用户", + "last_updated": time.time(), + "user_name": "" + } + self._update_cache(user_id, default_score, "新用户") + return default_result + + except Exception as e: + logger.error(f"获取用户关系数据失败: {user_id}, 错误: {e}") + return { + "relationship_score": global_config.affinity_flow.base_relationship_score, + "relationship_text": "新用户", + "last_updated": time.time(), + "user_name": "" + } + + async def update_user_relationship(self, user_id: str, relationship_score: float, relationship_text: Optional[str] = None, user_name: Optional[str] = None): + """ + 更新用户关系数据 + + Args: + user_id: 用户ID + relationship_score: 关系分 (0.0 - 1.0) + relationship_text: 关系描述文本 + user_name: 用户名称 + """ + try: + # 限制分数范围 + score = max(0.0, min(1.0, relationship_score)) + + async with get_db_session() as session: + # 查找现有记录 + from sqlalchemy import select + stmt = select(UserRelationships).where(UserRelationships.user_id == user_id) + result = await session.execute(stmt) + existing = result.scalar_one_or_none() + + if existing: + # 更新现有记录 + existing.relationship_score = score + existing.last_updated = time.time() + if relationship_text is not None: + existing.relationship_text = relationship_text + if user_name is not None: + existing.user_name = user_name + logger.debug(f"更新用户关系: {user_id} -> {score:.3f}") + else: + # 创建新记录 + new_relationship = UserRelationships( + user_id=user_id, + user_name=user_name or "", + relationship_text=relationship_text or "新用户", + relationship_score=score, + last_updated=time.time() + ) + session.add(new_relationship) + logger.debug(f"创建用户关系: {user_id} -> {score:.3f}") + + await session.commit() + + # 更新缓存 + self._update_cache(user_id, score, relationship_text or "新用户") + + except Exception as e: + logger.error(f"更新用户关系失败: {user_id}, 错误: {e}") + + def _get_from_cache(self, user_id: str) -> Optional[dict]: + """从缓存获取数据""" + if user_id in self._cache: + cached_data = self._cache[user_id] + if time.time() - cached_data["last_updated"] < self._cache_ttl: + return cached_data + else: + # 缓存过期,删除 + del self._cache[user_id] + return None + + def _update_cache(self, user_id: str, score: float, text: str): + """更新缓存""" + self._cache[user_id] = { + "score": score, + "text": text, + "last_updated": time.time() + } + + async def _fetch_from_database(self, user_id: str) -> Optional[UserRelationships]: + """从数据库获取关系数据""" + try: + async with get_db_session() as session: + from sqlalchemy import select + stmt = select(UserRelationships).where(UserRelationships.user_id == user_id) + result = await session.execute(stmt) + return result.scalar_one_or_none() + except Exception as e: + logger.error(f"从数据库获取关系数据失败: {user_id}, 错误: {e}") + return None + + async def _create_default_relationship(self, user_id: str): + """创建默认关系记录""" + try: + default_score = global_config.affinity_flow.base_relationship_score + async with get_db_session() as session: + new_relationship = UserRelationships( + user_id=user_id, + user_name="", + relationship_text="新用户", + relationship_score=default_score, + last_updated=time.time() + ) + session.add(new_relationship) + await session.commit() + logger.debug(f"创建默认关系记录: {user_id} -> {default_score:.3f}") + except Exception as e: + logger.error(f"创建默认关系记录失败: {user_id}, 错误: {e}") + + def get_cache_stats(self) -> dict: + """获取缓存统计信息""" + return { + "cached_users": len(self._cache), + "cache_ttl": self._cache_ttl, + "cache_keys": list(self._cache.keys()) + } + + def clear_cache(self, user_id: Optional[str] = None): + """清理缓存""" + if user_id: + if user_id in self._cache: + del self._cache[user_id] + logger.debug(f"清理用户缓存: {user_id}") + else: + self._cache.clear() + logger.debug("清理所有缓存") + + +# 创建全局实例 +relationship_service = RelationshipService() \ No newline at end of file diff --git a/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py b/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py deleted file mode 100644 index f3b41c15e..000000000 --- a/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py +++ /dev/null @@ -1,333 +0,0 @@ -""" -兴趣度评分系统 -基于多维度评分机制,包括兴趣匹配度、用户关系分、提及度和时间因子 -现在使用embedding计算智能兴趣匹配 -""" - -import traceback -from typing import Any - -from src.chat.interest_system import bot_interest_manager -from src.common.data_models.database_data_model import DatabaseMessages -from src.common.data_models.info_data_model import InterestScore -from src.common.logger import get_logger -from src.config.config import global_config - -logger = get_logger("chatter_interest_scoring") - -# 定义颜色 -SOFT_BLUE = "\033[38;5;67m" -RESET_COLOR = "\033[0m" - - -class ChatterInterestScoringSystem: - """兴趣度评分系统""" - - def __init__(self): - # 智能兴趣匹配配置 - self.use_smart_matching = True - - # 从配置加载评分权重 - affinity_config = global_config.affinity_flow - self.score_weights = { - "interest_match": affinity_config.keyword_match_weight, # 兴趣匹配度权重 - "relationship": affinity_config.relationship_weight, # 关系分权重 - "mentioned": affinity_config.mention_bot_weight, # 是否提及bot权重 - } - - # 评分阈值 - self.reply_threshold = affinity_config.reply_action_interest_threshold # 回复动作兴趣阈值 - self.mention_threshold = affinity_config.mention_bot_adjustment_threshold # 提及bot后的调整阈值 - - # 连续不回复概率提升 - self.no_reply_count = 0 - self.max_no_reply_count = affinity_config.max_no_reply_count - self.probability_boost_per_no_reply = ( - affinity_config.no_reply_threshold_adjustment / affinity_config.max_no_reply_count - ) # 每次不回复增加的概率 - - # 用户关系数据 - self.user_relationships: dict[str, float] = {} # user_id -> relationship_score - - async def calculate_interest_scores( - self, messages: list[DatabaseMessages], bot_nickname: str - ) -> list[InterestScore]: - """计算消息的兴趣度评分""" - user_messages = [msg for msg in messages if str(msg.user_info.user_id) != str(global_config.bot.qq_account)] - if not user_messages: - return [] - - scores = [] - for _, msg in enumerate(user_messages, 1): - score = await self._calculate_single_message_score(msg, bot_nickname) - scores.append(score) - - return scores - - async def _calculate_single_message_score(self, message: DatabaseMessages, bot_nickname: str) -> InterestScore: - """计算单条消息的兴趣度评分""" - - keywords = self._extract_keywords_from_database(message) - interest_match_score = await self._calculate_interest_match_score(message.processed_plain_text, keywords) - relationship_score = await self._calculate_relationship_score(message.user_info.user_id) - mentioned_score = self._calculate_mentioned_score(message, bot_nickname) - - total_score = ( - interest_match_score * self.score_weights["interest_match"] - + relationship_score * self.score_weights["relationship"] - + mentioned_score * self.score_weights["mentioned"] - ) - - details = { - "interest_match": f"兴趣匹配: {interest_match_score:.3f}", - "relationship": f"关系: {relationship_score:.3f}", - "mentioned": f"提及: {mentioned_score:.3f}", - } - - logger.debug( - f"消息得分详情: {total_score:.3f} (匹配: {interest_match_score:.2f}, 关系: {relationship_score:.2f}, 提及: {mentioned_score:.2f})" - ) - - return InterestScore( - message_id=message.message_id, - total_score=total_score, - interest_match_score=interest_match_score, - relationship_score=relationship_score, - mentioned_score=mentioned_score, - details=details, - ) - - async def _calculate_interest_match_score(self, content: str, keywords: list[str] | None = None) -> float: - """计算兴趣匹配度 - 使用智能embedding匹配""" - if not content: - return 0.0 - - # 使用智能匹配(embedding) - if self.use_smart_matching and bot_interest_manager.is_initialized: - return await self._calculate_smart_interest_match(content, keywords) - else: - # 智能匹配未初始化,返回默认分数 - return 0.3 - - async def _calculate_smart_interest_match(self, content: str, keywords: list[str] | None = None) -> float: - """使用embedding计算智能兴趣匹配""" - try: - # 如果没有传入关键词,则提取 - if not keywords: - keywords = self._extract_keywords_from_content(content) - - # 使用机器人兴趣管理器计算匹配度 - match_result = await bot_interest_manager.calculate_interest_match(content, keywords) - - if match_result: - # 返回匹配分数,考虑置信度和匹配标签数量 - affinity_config = global_config.affinity_flow - match_count_bonus = min( - len(match_result.matched_tags) * affinity_config.match_count_bonus, affinity_config.max_match_bonus - ) - final_score = match_result.overall_score * 1.15 * match_result.confidence + match_count_bonus - return final_score - else: - return 0.0 - - except Exception as e: - logger.error(f"智能兴趣匹配计算失败: {e}") - return 0.0 - - def _extract_keywords_from_database(self, message: DatabaseMessages) -> list[str]: - """从数据库消息中提取关键词""" - keywords = [] - - # 尝试从 key_words 字段提取(存储的是JSON字符串) - if message.key_words: - try: - import orjson - - keywords = orjson.loads(message.key_words) - if not isinstance(keywords, list): - keywords = [] - except (orjson.JSONDecodeError, TypeError): - keywords = [] - - # 如果没有 keywords,尝试从 key_words_lite 提取 - if not keywords and message.key_words_lite: - try: - import orjson - - keywords = orjson.loads(message.key_words_lite) - if not isinstance(keywords, list): - keywords = [] - except (orjson.JSONDecodeError, TypeError): - keywords = [] - - # 如果还是没有,从消息内容中提取(降级方案) - if not keywords: - keywords = self._extract_keywords_from_content(message.processed_plain_text) - - return keywords[:15] # 返回前15个关键词 - - def _extract_keywords_from_content(self, content: str) -> list[str]: - """从内容中提取关键词(降级方案)""" - import re - - # 清理文本 - content = re.sub(r"[^\w\s\u4e00-\u9fff]", " ", content) # 保留中文、英文、数字 - words = content.split() - - # 过滤和关键词提取 - keywords = [] - for word in words: - word = word.strip() - if ( - len(word) >= 2 # 至少2个字符 - and word.isalnum() # 字母数字 - and not word.isdigit() - ): # 不是纯数字 - keywords.append(word.lower()) - - # 去重并限制数量 - unique_keywords = list(set(keywords)) - return unique_keywords[:10] # 返回前10个唯一关键词 - - async def _calculate_relationship_score(self, user_id: str) -> float: - """计算关系分 - 从数据库获取关系分""" - # 优先使用内存中的关系分 - if user_id in self.user_relationships: - relationship_value = self.user_relationships[user_id] - return min(relationship_value, 1.0) - - # 如果内存中没有,尝试从关系追踪器获取 - if hasattr(self, "relationship_tracker") and self.relationship_tracker: - try: - relationship_score = await self.relationship_tracker.get_user_relationship_score(user_id) - # 同时更新内存缓存 - self.user_relationships[user_id] = relationship_score - return relationship_score - except Exception: - pass - else: - # 尝试从全局关系追踪器获取 - try: - from .relationship_tracker import ChatterRelationshipTracker - - global_tracker = ChatterRelationshipTracker() - if global_tracker: - relationship_score = await global_tracker.get_user_relationship_score(user_id) - # 同时更新内存缓存 - self.user_relationships[user_id] = relationship_score - return relationship_score - except Exception: - pass - - # 默认新用户的基础分 - return global_config.affinity_flow.base_relationship_score - - def _calculate_mentioned_score(self, msg: DatabaseMessages, bot_nickname: str) -> float: - """计算提及分数""" - if not msg.processed_plain_text: - return 0.0 - - # 检查是否被提及 - bot_aliases = [bot_nickname, *global_config.bot.alias_names] - is_mentioned = msg.is_mentioned or any(alias in msg.processed_plain_text for alias in bot_aliases if alias) - - # 如果被提及或是私聊,都视为提及了bot - if is_mentioned or not hasattr(msg, "chat_info_group_id"): - return global_config.affinity_flow.mention_bot_interest_score - - return 0.0 - - def should_reply(self, score: InterestScore, message: "DatabaseMessages") -> bool: - """判断是否应该回复""" - base_threshold = self.reply_threshold - - # 如果被提及,降低阈值 - if score.mentioned_score >= global_config.affinity_flow.mention_bot_adjustment_threshold: - base_threshold = self.mention_threshold - - # 计算连续不回复的概率提升 - probability_boost = min(self.no_reply_count * self.probability_boost_per_no_reply, 0.8) - effective_threshold = base_threshold - probability_boost - - # 做出决策 - should_reply = score.total_score >= effective_threshold - decision = "回复" if should_reply else "不回复" - logger.info( - f"{SOFT_BLUE}决策: {decision} (兴趣度: {score.total_score:.3f} / 阈值: {effective_threshold:.3f}){RESET_COLOR}" - ) - - return should_reply, score.total_score - - def record_reply_action(self, did_reply: bool): - """记录回复动作""" - old_count = self.no_reply_count - if did_reply: - self.no_reply_count = max(0, self.no_reply_count - global_config.affinity_flow.reply_cooldown_reduction) - action = "回复" - else: - self.no_reply_count += 1 - action = "不回复" - - # 限制最大计数 - self.no_reply_count = min(self.no_reply_count, self.max_no_reply_count) - logger.info(f"动作: {action}, 连续不回复次数: {old_count} -> {self.no_reply_count}") - - def update_user_relationship(self, user_id: str, relationship_change: float): - """更新用户关系""" - old_score = self.user_relationships.get( - user_id, global_config.affinity_flow.base_relationship_score - ) # 默认新用户分数 - new_score = max(0.0, min(1.0, old_score + relationship_change)) - - self.user_relationships[user_id] = new_score - - logger.info(f"用户关系: {user_id} | {old_score:.3f} → {new_score:.3f}") - - def get_user_relationship(self, user_id: str) -> float: - """获取用户关系分""" - return self.user_relationships.get(user_id, 0.3) - - def get_scoring_stats(self) -> dict: - """获取评分系统统计""" - return { - "no_reply_count": self.no_reply_count, - "max_no_reply_count": self.max_no_reply_count, - "reply_threshold": self.reply_threshold, - "mention_threshold": self.mention_threshold, - "user_relationships": len(self.user_relationships), - } - - def reset_stats(self): - """重置统计信息""" - self.no_reply_count = 0 - logger.info("重置兴趣度评分系统统计") - - async def initialize_smart_interests(self, personality_description: str, personality_id: str = "default"): - """初始化智能兴趣系统""" - try: - logger.info("开始初始化智能兴趣系统...") - logger.info(f"人设ID: {personality_id}, 描述长度: {len(personality_description)}") - - await bot_interest_manager.initialize(personality_description, personality_id) - logger.info("智能兴趣系统初始化完成。") - - # 显示初始化后的统计信息 - bot_interest_manager.get_interest_stats() - - except Exception as e: - logger.error(f"初始化智能兴趣系统失败: {e}") - traceback.print_exc() - - def get_matching_config(self) -> dict[str, Any]: - """获取匹配配置信息""" - return { - "use_smart_matching": self.use_smart_matching, - "smart_system_initialized": bot_interest_manager.is_initialized, - "smart_system_stats": bot_interest_manager.get_interest_stats() - if bot_interest_manager.is_initialized - else None, - } - - -# 创建全局兴趣评分系统实例 -chatter_interest_scoring_system = ChatterInterestScoringSystem() diff --git a/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py index 8aade9c79..68c2fb73a 100644 --- a/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py +++ b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py @@ -27,7 +27,9 @@ class ChatterRelationshipTracker: self.update_interval_minutes = 30 self.last_update_time = time.time() self.relationship_history: list[dict] = [] - self.interest_scoring_system = interest_scoring_system + + # 兼容性:保留参数但不直接使用,转而使用统一API + self.interest_scoring_system = None # 废弃,不再使用 # 用户关系缓存 (user_id -> {"relationship_text": str, "relationship_score": float, "last_tracked": float}) self.user_relationship_cache: dict[str, dict] = {} @@ -63,8 +65,9 @@ class ChatterRelationshipTracker: ) def set_interest_scoring_system(self, interest_scoring_system): - """设置兴趣度评分系统引用""" - self.interest_scoring_system = interest_scoring_system + """设置兴趣度评分系统引用(已废弃,使用统一API)""" + # 不再需要设置,直接使用统一API + logger.info("set_interest_scoring_system 已废弃,现在使用统一评分API") def add_interaction(self, user_id: str, user_name: str, user_message: str, bot_reply: str, reply_timestamp: float): """添加用户交互记录""" @@ -75,10 +78,10 @@ class ChatterRelationshipTracker: ) del self.tracking_users[oldest_user] - # 获取当前关系分 + # 获取当前关系分 - 使用缓存数据 current_relationship_score = global_config.affinity_flow.base_relationship_score # 默认值 - if self.interest_scoring_system: - current_relationship_score = self.interest_scoring_system.get_user_relationship(user_id) + if user_id in self.user_relationship_cache: + current_relationship_score = self.user_relationship_cache[user_id].get("relationship_score", current_relationship_score) self.tracking_users[user_id] = { "user_id": user_id, @@ -178,10 +181,11 @@ class ChatterRelationshipTracker: ), ) - if self.interest_scoring_system: - self.interest_scoring_system.update_user_relationship( - interaction["user_id"], new_score - interaction["current_relationship_score"] - ) + # 使用统一API更新关系分 + from src.plugin_system.apis.scoring_api import scoring_api + await scoring_api.update_user_relationship( + interaction["user_id"], new_score + ) return { "user_id": interaction["user_id"], @@ -252,12 +256,14 @@ class ChatterRelationshipTracker: self.update_interval_minutes = update_interval_minutes logger.info(f"更新关系更新间隔: {update_interval_minutes} 分钟") - def force_update_relationship(self, user_id: str, new_score: float, reasoning: str = ""): + async def force_update_relationship(self, user_id: str, new_score: float, reasoning: str = ""): """强制更新用户关系分""" if user_id in self.tracking_users: current_score = self.tracking_users[user_id]["current_relationship_score"] - if self.interest_scoring_system: - self.interest_scoring_system.update_user_relationship(user_id, new_score - current_score) + + # 使用统一API更新关系分 + from src.plugin_system.apis.scoring_api import scoring_api + await scoring_api.update_user_relationship(user_id, new_score) update_info = { "user_id": user_id, @@ -605,9 +611,8 @@ class ChatterRelationshipTracker: "last_tracked": time.time(), } - # 如果有兴趣度评分系统,也更新内存中的关系分 - if self.interest_scoring_system: - self.interest_scoring_system.update_user_relationship(user_id, new_score - current_score) + # 使用统一API更新关系分(内存缓存已通过数据库更新自动处理) + # 数据库更新后,缓存会在下次访问时自动同步 # 记录分析历史 analysis_record = {