diff --git a/src/chat/affinity_flow/__init__.py b/src/chat/affinity_flow/__init__.py deleted file mode 100644 index 1991738a9..000000000 --- a/src/chat/affinity_flow/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -亲和力流模块初始化文件 -提供全局的AFC管理器实例 -""" - -# Avoid importing submodules at package import time to prevent circular imports. -# Consumers should import specific submodules directly, for example: -# from src.chat.affinity_flow.afc_manager import afc_manager - -__all__ = ["afc_manager", "AFCManager", "AffinityFlowChatter"] diff --git a/src/chat/affinity_flow/afc_manager.py b/src/chat/affinity_flow/afc_manager.py deleted file mode 100644 index 9555ee5ea..000000000 --- a/src/chat/affinity_flow/afc_manager.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -亲和力聊天处理流管理器 -管理不同聊天流的亲和力聊天处理流,统一获取新消息并分发到对应的亲和力聊天处理流 -""" - -import time -import traceback -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") - - -class AFCManager: - """亲和力聊天处理流管理器""" - - def __init__(self): - self.affinity_flow_chatters: Dict[str, "AffinityFlowChatter"] = {} - """所有聊天流的亲和力聊天处理流,stream_id -> affinity_flow_chatter""" - - # 动作管理器 - self.action_manager = ActionManager() - - # 管理器统计 - self.manager_stats = { - "total_messages_processed": 0, - "total_plans_created": 0, - "total_actions_executed": 0, - "active_chatters": 0, - "last_activity_time": time.time(), - } - - def get_or_create_chatter(self, stream_id: str) -> "AffinityFlowChatter": - """获取或创建聊天流处理器""" - if stream_id not in self.affinity_flow_chatters: - # 创建增强版规划器 - planner = ActionPlanner(stream_id, self.action_manager) - - chatter = AffinityFlowChatter(stream_id=stream_id, planner=planner, action_manager=self.action_manager) - self.affinity_flow_chatters[stream_id] = chatter - logger.info(f"创建新的亲和力聊天处理器: {stream_id}") - - return self.affinity_flow_chatters[stream_id] - - async def process_stream_context(self, stream_id: str, context: StreamContext) -> Dict[str, any]: - """处理StreamContext对象""" - try: - # 获取或创建聊天处理器 - chatter = self.get_or_create_chatter(stream_id) - - # 处理StreamContext - result = await chatter.process_stream_context(context) - - # 更新统计 - self.manager_stats["total_messages_processed"] += 1 - self.manager_stats["total_actions_executed"] += result.get("executed_count", 0) - self.manager_stats["last_activity_time"] = time.time() - - return result - - except Exception as e: - logger.error(f"处理StreamContext时出错: {e}\n{traceback.format_exc()}") - return { - "success": False, - "error_message": str(e), - "executed_count": 0, - } - - def get_chatter_stats(self, stream_id: str) -> Optional[Dict[str, any]]: - """获取聊天处理器统计""" - if stream_id in self.affinity_flow_chatters: - return self.affinity_flow_chatters[stream_id].get_stats() - return None - - def get_manager_stats(self) -> Dict[str, any]: - """获取管理器统计""" - stats = self.manager_stats.copy() - stats["active_chatters"] = len(self.affinity_flow_chatters) - return stats - - def cleanup_inactive_chatters(self, max_inactive_minutes: int = 60): - """清理不活跃的聊天处理器""" - current_time = time.time() - max_inactive_seconds = max_inactive_minutes * 60 - - inactive_streams = [] - for stream_id, chatter in self.affinity_flow_chatters.items(): - if current_time - chatter.last_activity_time > max_inactive_seconds: - inactive_streams.append(stream_id) - - for stream_id in inactive_streams: - del self.affinity_flow_chatters[stream_id] - logger.info(f"清理不活跃聊天处理器: {stream_id}") - - def get_planner_stats(self, stream_id: str) -> Optional[Dict[str, any]]: - """获取规划器统计""" - if stream_id in self.affinity_flow_chatters: - return self.affinity_flow_chatters[stream_id].get_planner_stats() - return None - - def get_interest_scoring_stats(self, stream_id: str) -> Optional[Dict[str, any]]: - """获取兴趣度评分统计""" - if stream_id in self.affinity_flow_chatters: - return self.affinity_flow_chatters[stream_id].get_interest_scoring_stats() - return None - - def get_relationship_stats(self, stream_id: str) -> Optional[Dict[str, any]]: - """获取用户关系统计""" - if stream_id in self.affinity_flow_chatters: - return self.affinity_flow_chatters[stream_id].get_relationship_stats() - return None - - def get_user_relationship(self, stream_id: str, user_id: str) -> float: - """获取用户关系分""" - if stream_id in self.affinity_flow_chatters: - return self.affinity_flow_chatters[stream_id].get_user_relationship(user_id) - return 0.3 # 默认新用户关系分 - - def update_interest_keywords(self, stream_id: str, new_keywords: dict): - """更新兴趣关键词""" - if stream_id in self.affinity_flow_chatters: - self.affinity_flow_chatters[stream_id].update_interest_keywords(new_keywords) - logger.info(f"已更新聊天流 {stream_id} 的兴趣关键词: {list(new_keywords.keys())}") - - -afc_manager = AFCManager() diff --git a/src/chat/affinity_flow/chatter.py b/src/chat/affinity_flow/chatter.py deleted file mode 100644 index 92e46963c..000000000 --- a/src/chat/affinity_flow/chatter.py +++ /dev/null @@ -1,206 +0,0 @@ -""" -亲和力聊天处理器 -单个聊天流的处理器,负责处理特定聊天流的完整交互流程 -""" - -import time -import traceback -from datetime import datetime -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.base_chatter import BaseChatter -from src.plugin_system.base.component_types import ChatMode - -from src.common.logger import get_logger - -logger = get_logger("affinity_chatter") - - -class AffinityFlowChatter(BaseChatter): - """单个亲和力聊天处理器""" - - def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager): - """ - 初始化亲和力聊天处理器 - - Args: - stream_id: 聊天流ID - planner: 动作规划器 - action_manager: 动作管理器 - """ - self.stream_id = stream_id - self.planner = planner - self.action_manager = action_manager - - # 处理器统计 - self.stats = { - "messages_processed": 0, - "plans_created": 0, - "actions_executed": 0, - "successful_executions": 0, - "failed_executions": 0, - } - self.last_activity_time = time.time() - - async def execute(self, context: StreamContext) -> dict: - """ - 处理StreamContext对象 - - Args: - context: StreamContext对象,包含聊天流的所有消息信息 - - Returns: - 处理结果字典 - """ - try: - unread_messages = context.get_unread_messages() - - # 使用增强版规划器处理消息 - actions, target_message = await self.planner.plan(mode=ChatMode.FOCUS, 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)} 个动作") - - # 更新统计 - self.stats["messages_processed"] += 1 - self.stats["actions_executed"] += execution_result.get("executed_count", 0) - self.stats["successful_executions"] += 1 - self.last_activity_time = time.time() - - result = { - "success": True, - "stream_id": self.stream_id, - "plan_created": True, - "actions_count": len(actions) if actions else 0, - "has_target_message": target_message is not None, - "unread_messages_processed": len(unread_messages), - **execution_result, - } - - logger.info( - f"聊天流 {self.stream_id} StreamContext处理成功: 动作数={result['actions_count']}, 未读消息={result['unread_messages_processed']}" - ) - - return result - - except Exception as e: - logger.error(f"亲和力聊天处理器 {self.stream_id} 处理StreamContext时出错: {e}\n{traceback.format_exc()}") - self.stats["failed_executions"] += 1 - self.last_activity_time = time.time() - - return { - "success": False, - "stream_id": self.stream_id, - "error_message": str(e), - "executed_count": 0, - } - - def get_stats(self) -> Dict[str, any]: - """ - 获取处理器统计信息 - - Returns: - 统计信息字典 - """ - return self.stats.copy() - - def get_planner_stats(self) -> Dict[str, any]: - """ - 获取规划器统计信息 - - Returns: - 规划器统计信息字典 - """ - return self.planner.get_planner_stats() - - def get_interest_scoring_stats(self) -> Dict[str, any]: - """ - 获取兴趣度评分统计信息 - - Returns: - 兴趣度评分统计信息字典 - """ - return self.planner.get_interest_scoring_stats() - - def get_relationship_stats(self) -> Dict[str, any]: - """ - 获取用户关系统计信息 - - Returns: - 用户关系统计信息字典 - """ - return self.planner.get_relationship_stats() - - def get_user_relationship(self, user_id: str) -> float: - """ - 获取用户关系分 - - Args: - user_id: 用户ID - - Returns: - 用户关系分 (0.0-1.0) - """ - return self.planner.get_user_relationship(user_id) - - def update_interest_keywords(self, new_keywords: dict): - """ - 更新兴趣关键词 - - Args: - new_keywords: 新的兴趣关键词字典 - """ - self.planner.update_interest_keywords(new_keywords) - logger.info(f"聊天流 {self.stream_id} 已更新兴趣关键词: {list(new_keywords.keys())}") - - def reset_stats(self): - """重置统计信息""" - self.stats = { - "messages_processed": 0, - "plans_created": 0, - "actions_executed": 0, - "successful_executions": 0, - "failed_executions": 0, - } - - def is_active(self, max_inactive_minutes: int = 60) -> bool: - """ - 检查处理器是否活跃 - - Args: - max_inactive_minutes: 最大不活跃分钟数 - - Returns: - 是否活跃 - """ - current_time = time.time() - max_inactive_seconds = max_inactive_minutes * 60 - return (current_time - self.last_activity_time) < max_inactive_seconds - - def get_activity_time(self) -> float: - """ - 获取最后活动时间 - - Returns: - 最后活动时间戳 - """ - return self.last_activity_time - - def __str__(self) -> str: - """字符串表示""" - return f"AffinityFlowChatter(stream_id={self.stream_id}, messages={self.stats['messages_processed']})" - - def __repr__(self) -> str: - """详细字符串表示""" - return ( - f"AffinityFlowChatter(stream_id={self.stream_id}, " - f"messages_processed={self.stats['messages_processed']}, " - f"plans_created={self.stats['plans_created']}, " - f"last_activity={datetime.fromtimestamp(self.last_activity_time)})" - ) diff --git a/src/chat/affinity_flow/relationship_integration.py b/src/chat/affinity_flow/relationship_integration.py deleted file mode 100644 index 8b01e2587..000000000 --- a/src/chat/affinity_flow/relationship_integration.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -回复后关系追踪集成初始化脚本 - -此脚本用于设置回复后关系追踪系统的全局变量和初始化连接 -确保各组件能正确协同工作 -""" - -from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker -from src.chat.affinity_flow.interest_scoring import interest_scoring_system -from src.common.logger import get_logger - -logger = get_logger("relationship_integration") - -# 全局关系追踪器实例 -relationship_tracker = None - - -def initialize_relationship_tracking(): - """初始化关系追踪系统""" - global relationship_tracker - - try: - logger.info("🚀 初始化回复后关系追踪系统...") - - # 创建关系追踪器实例 - relationship_tracker = UserRelationshipTracker(interest_scoring_system=interest_scoring_system) - - # 设置兴趣度评分系统的关系追踪器引用 - interest_scoring_system.relationship_tracker = relationship_tracker - - logger.info("✅ 回复后关系追踪系统初始化完成") - logger.info("📋 系统功能:") - logger.info(" 🔄 自动回复后关系追踪") - logger.info(" 💾 数据库持久化存储") - logger.info(" 🧠 LLM智能关系分析") - logger.info(" ⏰ 5分钟追踪间隔") - logger.info(" 🎯 兴趣度评分集成") - - return relationship_tracker - - except Exception as e: - logger.error(f"❌ 关系追踪系统初始化失败: {e}") - logger.debug("错误详情:", exc_info=True) - return None - - -def get_relationship_tracker(): - """获取全局关系追踪器实例""" - global relationship_tracker - return relationship_tracker - - -def setup_plan_executor_relationship_tracker(plan_executor): - """为PlanExecutor设置关系追踪器""" - global relationship_tracker - - if relationship_tracker and plan_executor: - plan_executor.set_relationship_tracker(relationship_tracker) - logger.info("✅ PlanExecutor关系追踪器设置完成") - return True - - logger.warning("⚠️ 无法设置PlanExecutor关系追踪器") - return False - - -# 自动初始化 -if __name__ == "__main__": - initialize_relationship_tracking() diff --git a/src/chat/chatter_manager.py b/src/chat/chatter_manager.py index 6b09938a0..5c4c60489 100644 --- a/src/chat/chatter_manager.py +++ b/src/chat/chatter_manager.py @@ -2,15 +2,15 @@ from typing import Dict, List, Optional, Any import time from src.plugin_system.base.base_chatter import BaseChatter from src.common.data_models.message_manager_data_model import StreamContext -from src.chat.planner_actions.planner import ActionPlanner -from src.chat.planner_actions.action_manager import ActionManager +from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner +from src.chat.planner_actions.action_manager import ChatterActionManager from src.plugin_system.base.component_types import ChatType, ComponentType from src.common.logger import get_logger logger = get_logger("chatter_manager") class ChatterManager: - def __init__(self, action_manager: ActionManager): + def __init__(self, action_manager: ChatterActionManager): self.action_manager = action_manager self.chatter_classes: Dict[ChatType, List[type]] = {} self.instances: Dict[str, BaseChatter] = {} diff --git a/src/chat/frequency_analyzer/trigger.py b/src/chat/frequency_analyzer/trigger.py index 156d300dd..2d8e8b56f 100644 --- a/src/chat/frequency_analyzer/trigger.py +++ b/src/chat/frequency_analyzer/trigger.py @@ -21,7 +21,7 @@ from datetime import datetime from typing import Dict, Optional from src.common.logger import get_logger -from src.chat.affinity_flow.afc_manager import afc_manager +# AFC manager has been moved to chatter plugin # TODO: 需要重新实现主动思考和睡眠管理功能 from .analyzer import chat_frequency_analyzer @@ -61,8 +61,9 @@ class FrequencyBasedTrigger: # continue # 2. 获取所有已知的聊天ID - # 亲和力流系统中聊天ID直接从管理器获取 - all_chat_ids = list(afc_manager.affinity_flow_chatters.keys()) + # 注意:AFC管理器已移至chatter插件,此功能暂时禁用 + # all_chat_ids = list(afc_manager.affinity_flow_chatters.keys()) + all_chat_ids = [] # 暂时禁用此功能 if not all_chat_ids: continue @@ -77,26 +78,10 @@ class FrequencyBasedTrigger: # 4. 检查当前是否是该用户的高峰聊天时间 if chat_frequency_analyzer.is_in_peak_time(chat_id, now): # 5. 检查用户当前是否已有活跃的处理任务 - # 亲和力流系统不直接提供循环状态,通过检查最后活动时间来判断是否忙碌 - chatter = afc_manager.get_or_create_chatter(chat_id) - if not chatter: - logger.warning(f"无法为 {chat_id} 获取或创建亲和力聊天处理器。") - continue - - # 检查是否在活跃状态(最近1分钟内有活动) - current_time = time.time() - if current_time - chatter.get_activity_time() < 60: - logger.debug(f"用户 {chat_id} 的亲和力处理器正忙,本次不触发。") - continue - - logger.info(f"检测到用户 {chat_id} 处于聊天高峰期,且处理器空闲,准备触发主动思考。") - - # 6. TODO: 亲和力流系统的主动思考机制需要另行实现 - # 目前先记录日志,等待后续实现 - logger.info(f"用户 {chat_id} 处于高峰期,但亲和力流的主动思考功能暂未实现") - - # 7. 更新触发时间,进入冷却 - self._last_triggered[chat_id] = time.time() + # 注意:AFC管理器已移至chatter插件,此功能暂时禁用 + # chatter = afc_manager.get_or_create_chatter(chat_id) + logger.info(f"检测到用户 {chat_id} 处于聊天高峰期,但AFC功能已移至chatter插件") + continue except asyncio.CancelledError: logger.info("频率触发器任务被取消。") diff --git a/src/chat/message_manager/message_manager.py b/src/chat/message_manager/message_manager.py index d0e8c62c3..c012691e1 100644 --- a/src/chat/message_manager/message_manager.py +++ b/src/chat/message_manager/message_manager.py @@ -12,7 +12,7 @@ from src.common.logger import get_logger from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.message_manager_data_model import StreamContext, MessageManagerStats, StreamStats from src.chat.chatter_manager import ChatterManager -from src.chat.planner_actions.action_manager import ActionManager +from src.chat.planner_actions.action_manager import ChatterActionManager if TYPE_CHECKING: from src.common.data_models.message_manager_data_model import StreamContext @@ -33,7 +33,7 @@ class MessageManager: self.stats = MessageManagerStats() # 初始化chatter manager - self.action_manager = ActionManager() + self.action_manager = ChatterActionManager() self.chatter_manager = ChatterManager(self.action_manager) async def start(self): diff --git a/src/chat/planner_actions/action_manager.py b/src/chat/planner_actions/action_manager.py index 4cc2c2a1d..c6287ca00 100644 --- a/src/chat/planner_actions/action_manager.py +++ b/src/chat/planner_actions/action_manager.py @@ -18,7 +18,7 @@ from src.plugin_system.apis import generator_api, database_api, send_api, messag logger = get_logger("action_manager") -class ActionManager: +class ChatterActionManager: """ 动作管理器,用于管理各种类型的动作 @@ -34,7 +34,7 @@ class ActionManager: # 初始化时将默认动作加载到使用中的动作 self._using_actions = component_registry.get_default_actions() - self.log_prefix: str = "ActionManager" + self.log_prefix: str = "ChatterActionManager" # === 执行Action方法 === @@ -449,7 +449,7 @@ class ActionManager: data = "".join(map(str, data)) reply_text += data - # 如果是主动思考且内容为“沉默”,则不发送 + # 如果是主动思考且内容为"沉默",则不发送 if is_proactive_thinking and data.strip() == "沉默": logger.info(f"{self.log_prefix} 主动思考决定保持沉默,不发送消息") continue @@ -474,4 +474,4 @@ class ActionManager: typing=True, ) - return reply_text + return reply_text \ No newline at end of file diff --git a/src/chat/planner_actions/action_modifier.py b/src/chat/planner_actions/action_modifier.py index e9cc1d106..6d38fc32f 100644 --- a/src/chat/planner_actions/action_modifier.py +++ b/src/chat/planner_actions/action_modifier.py @@ -8,7 +8,7 @@ from src.common.logger import get_logger from src.config.config import global_config, model_config from src.llm_models.utils_model import LLMRequest from src.chat.message_receive.chat_stream import get_chat_manager, ChatMessageContext -from src.chat.planner_actions.action_manager import ActionManager +from src.chat.planner_actions.action_manager import ChatterActionManager from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat, build_readable_messages from src.plugin_system.base.component_types import ActionInfo, ActionActivationType from src.plugin_system.core.global_announcement_manager import global_announcement_manager @@ -27,7 +27,7 @@ class ActionModifier: 支持并行判定和智能缓存优化。 """ - def __init__(self, action_manager: ActionManager, chat_id: str): + def __init__(self, action_manager: ChatterActionManager, chat_id: str): """初始化动作处理器""" self.chat_id = chat_id self.chat_stream: ChatStream = get_chat_manager().get_stream(self.chat_id) # type: ignore diff --git a/src/chat/planner_actions/plan_generator.py b/src/chat/planner_actions/plan_generator.py deleted file mode 100644 index 26e05fcf1..000000000 --- a/src/chat/planner_actions/plan_generator.py +++ /dev/null @@ -1,132 +0,0 @@ -""" -PlanGenerator: 负责搜集和汇总所有决策所需的信息,生成一个未经筛选的“原始计划” (Plan)。 -""" - -import time -from typing import Dict - -from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat -from src.chat.utils.utils import get_chat_type_and_target_info -from src.common.data_models.database_data_model import DatabaseMessages -from src.common.data_models.info_data_model import Plan, TargetPersonInfo -from src.config.config import global_config -from src.plugin_system.base.component_types import ActionActivationType, ActionInfo, ChatMode, ChatType, ComponentType -from src.plugin_system.core.component_registry import component_registry - - -class PlanGenerator: - """ - PlanGenerator 负责在规划流程的初始阶段收集所有必要信息。 - - 它会汇总以下信息来构建一个“原始”的 Plan 对象,该对象后续会由 PlanFilter 进行筛选: - - 当前聊天信息 (ID, 目标用户) - - 当前可用的动作列表 - - 最近的聊天历史记录 - - Attributes: - chat_id (str): 当前聊天的唯一标识符。 - action_manager (ActionManager): 用于获取可用动作列表的管理器。 - """ - - def __init__(self, chat_id: str): - """ - 初始化 PlanGenerator。 - - Args: - chat_id (str): 当前聊天的 ID。 - """ - from src.chat.planner_actions.action_manager import ActionManager - - self.chat_id = chat_id - # 注意:ActionManager 可能需要根据实际情况初始化 - self.action_manager = ActionManager() - - async def generate(self, mode: ChatMode) -> Plan: - """ - 收集所有信息,生成并返回一个初始的 Plan 对象。 - - 这个 Plan 对象包含了决策所需的所有上下文信息。 - - Args: - mode (ChatMode): 当前的聊天模式。 - - Returns: - Plan: 一个填充了初始上下文信息的 Plan 对象。 - """ - _is_group_chat, chat_target_info_dict = get_chat_type_and_target_info(self.chat_id) - - target_info = None - if chat_target_info_dict: - target_info = TargetPersonInfo(**chat_target_info_dict) - - available_actions = self._get_available_actions() - chat_history_raw = get_raw_msg_before_timestamp_with_chat( - chat_id=self.chat_id, - timestamp=time.time(), - limit=int(global_config.chat.max_context_size), - ) - chat_history = [DatabaseMessages(**msg) for msg in chat_history_raw] - - plan = Plan( - chat_id=self.chat_id, - mode=mode, - available_actions=available_actions, - chat_history=chat_history, - target_info=target_info, - ) - return plan - - def _get_available_actions(self) -> Dict[str, "ActionInfo"]: - """ - 从 ActionManager 和组件注册表中获取当前所有可用的动作。 - - 它会合并已注册的动作和系统级动作(如 "no_reply"), - 并以字典形式返回。 - - Returns: - Dict[str, "ActionInfo"]: 一个字典,键是动作名称,值是 ActionInfo 对象。 - """ - current_available_actions_dict = self.action_manager.get_using_actions() - all_registered_actions: Dict[str, ActionInfo] = component_registry.get_components_by_type( # type: ignore - ComponentType.ACTION - ) - - current_available_actions = {} - for action_name in current_available_actions_dict: - if action_name in all_registered_actions: - current_available_actions[action_name] = all_registered_actions[action_name] - - reply_info = ActionInfo( - name="reply", - component_type=ComponentType.ACTION, - description="系统级动作:选择回复消息的决策", - action_parameters={"content": "回复的文本内容", "reply_to_message_id": "要回复的消息ID"}, - action_require=[ - "你想要闲聊或者随便附和", - "当用户提到你或艾特你时", - "当需要回答用户的问题时", - "当你想参与对话时", - "当用户分享有趣的内容时", - ], - activation_type=ActionActivationType.ALWAYS, - activation_keywords=[], - associated_types=["text", "reply"], - plugin_name="SYSTEM", - enabled=True, - parallel_action=False, - mode_enable=ChatMode.ALL, - chat_type_allow=ChatType.ALL, - ) - no_reply_info = ActionInfo( - name="no_reply", - component_type=ComponentType.ACTION, - description="系统级动作:选择不回复消息的决策", - action_parameters={}, - activation_keywords=[], - plugin_name="SYSTEM", - enabled=True, - parallel_action=False, - ) - current_available_actions["no_reply"] = no_reply_info - current_available_actions["reply"] = reply_info - return current_available_actions diff --git a/src/chat/planner_actions/planner_prompts.py b/src/chat/planner_actions/planner_prompts.py deleted file mode 100644 index 7e509c8c8..000000000 --- a/src/chat/planner_actions/planner_prompts.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -本文件集中管理所有与规划器(Planner)相关的提示词(Prompt)模板。 - -通过将提示词与代码逻辑分离,可以更方便地对模型的行为进行迭代和优化, -而无需修改核心代码。 -""" - -from src.chat.utils.prompt import Prompt - - -def init_prompts(): - """ - 初始化并向 Prompt 注册系统注册所有规划器相关的提示词。 - - 这个函数会在模块加载时自动调用,确保所有提示词在系统启动时都已准备就绪。 - """ - # 核心规划器提示词,用于在接收到新消息时决定如何回应。 - # 它构建了一个复杂的上下文,包括历史记录、可用动作、角色设定等, - # 并要求模型以 JSON 格式输出一个或多个动作组合。 - Prompt( - """ -{mood_block} -{time_block} -{identity_block} - -{users_in_chat} -{custom_prompt_block} -{chat_context_description},以下是具体的聊天内容。 - -## 📜 已读历史消息(仅供参考) -{read_history_block} - -## 📬 未读历史消息(动作执行对象) -{unread_history_block} - -{moderation_prompt} - -**任务: 构建一个完整的响应** -你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成: -1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。 -2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。 - -**决策流程:** -1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。** -2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。** -3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。 -4. 首先,决定是否要对未读消息进行 `reply`(如果有)。 -5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。 -6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。 -7. 如果用户明确要求了某个动作,请务必优先满足。 - -**如果可选动作中没有reply,请不要使用** - -**可用动作:** -{actions_before_now_block} - -{no_action_block} - -{action_options_text} - - -**输出格式:** -你必须以严格的 JSON 格式输出,返回一个包含所有选定动作的JSON列表。如果没有任何合适的动作,返回一个空列表[]。 - -**单动作示例 (仅回复):** -[ - {{ - "action": "reply", - "target_message_id": "m123", - "reason": "回答用户的问题" - }} -] - -**组合动作示例 (回复 + 表情包):** -[ - {{ - "action": "reply", - "target_message_id": "m123", - "reason": "回答用户的问题" - }}, - {{ - "action": "emoji", - "target_message_id": "m123", - "reason": "根据我将要回复的文本内容,选择一个最匹配的表情包来增强表达效果。回复的文本是:" - }} -] - -**重要规则:** -1. 当 `reply` 和 `emoji` 动作同时被选择时,`emoji` 动作的 `reason` 字段必须包含 `reply` 动作最终生成的回复文本内容。你需要将 `` 占位符替换为 `reply` 动作的 `reason` 字段内容,以确保表情包的选择与回复文本高度相关。 -2. **动作执行限制:所有动作的target_message_id必须是未读历史消息中的消息ID(消息ID格式:m123)。** -3. **兴趣度优先:在多个未读消息中,优先选择兴趣值高的消息进行回复。** - -不要输出markdown格式```json等内容,直接输出且仅包含 JSON 列表内容: -""", - "planner_prompt", - ) - - # 主动思考规划器提示词,用于在没有新消息时决定是否要主动发起对话。 - # 它模拟了人类的自发性思考,允许模型根据长期记忆和最近的对话来决定是否开启新话题。 - Prompt( - """ -# 主动思考决策 - -## 你的内部状态 -{time_block} -{identity_block} -{mood_block} - -## 长期记忆摘要 -{long_term_memory_block} - -## 最近的聊天内容 -{chat_content_block} - -## 最近的动作历史 -{actions_before_now_block} - -## 任务 -你现在要决定是否主动说些什么。就像一个真实的人一样,有时候会突然想起之前聊到的话题,或者对朋友的近况感到好奇,想主动询问或关心一下。 -**重要提示**:你的日程安排仅供你个人参考,不应作为主动聊天话题的主要来源。请更多地从聊天内容和朋友的动态中寻找灵感。 - -请基于聊天内容,用你的判断力来决定是否要主动发言。不要按照固定规则,而是像人类一样自然地思考: -- 是否想起了什么之前提到的事情,想问问后来怎么样了? -- 是否注意到朋友提到了什么值得关心的事情? -- 是否有什么话题突然想到,觉得现在聊聊很合适? -- 或者觉得现在保持沉默更好? - -## 可用动作 -动作:proactive_reply -动作描述:主动发起对话,可以是关心朋友、询问近况、延续之前的话题,或分享想法。 -- 当你突然想起之前的话题,想询问进展时 -- 当你想关心朋友的情况时 -- 当你有什么想法想分享时 -- 当你觉得现在是个合适的聊天时机时 -{{ - "action": "proactive_reply", - "reason": "你决定主动发言的具体原因", - "topic": "你想说的内容主题(简洁描述)" -}} - -动作:do_nothing -动作描述:保持沉默,不主动发起对话。 -- 当你觉得现在不是合适的时机时 -- 当最近已经说得够多了时 -- 当对话氛围不适合插入时 -{{ - "action": "do_nothing", - "reason": "决定保持沉默的原因" -}} - -你必须从上面列出的可用action中选择一个。要像真人一样自然地思考和决策。 -请以严格的 JSON 格式输出,且仅包含 JSON 内容: -""", - "proactive_planner_prompt", - ) - - # 单个动作的格式化提示词模板。 - # 用于将每个可用动作的信息格式化后,插入到主提示词的 {action_options_text} 占位符中。 - Prompt( - """ -动作:{action_name} -动作描述:{action_description} -{action_require} -{{ - "action": "{action_name}", - "target_message_id": "触发action的消息id", - "reason": "触发action的原因"{action_parameters} -}} -""", - "action_prompt", - ) - - -# 在模块加载时自动调用,完成提示词的注册。 -init_prompts() diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index a720fd745..d841d4734 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -875,7 +875,7 @@ class DefaultReplyer: interest_scores = {} try: - from src.chat.affinity_flow.interest_scoring import interest_scoring_system + from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system from src.common.data_models.database_data_model import DatabaseMessages # 转换消息格式 @@ -1528,9 +1528,11 @@ class DefaultReplyer: # 使用AFC关系追踪器获取关系信息 try: - from src.chat.affinity_flow.relationship_integration import get_relationship_tracker + from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker - relationship_tracker = get_relationship_tracker() + # 创建关系追踪器实例 + from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system + 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"]) diff --git a/src/individuality/individuality.py b/src/individuality/individuality.py index 342bfaab5..3ff37d57d 100644 --- a/src/individuality/individuality.py +++ b/src/individuality/individuality.py @@ -84,7 +84,7 @@ class Individuality: full_personality = f"{personality_result},{identity_result}" # 获取全局兴趣评分系统实例 - from src.chat.affinity_flow.interest_scoring import interest_scoring_system + from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system # 初始化智能兴趣系统 await interest_scoring_system.initialize_smart_interests( diff --git a/src/main.py b/src/main.py index 9faee813d..333bdae7c 100644 --- a/src/main.py +++ b/src/main.py @@ -250,13 +250,16 @@ MoFox_Bot(第三方修改版) logger.info("表情包管理器初始化成功") # 初始化回复后关系追踪系统 - from src.chat.affinity_flow.relationship_integration import initialize_relationship_tracking + try: + from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system + from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker - relationship_tracker = initialize_relationship_tracking() - if relationship_tracker: + relationship_tracker = ChatterRelationshipTracker(interest_scoring_system=chatter_interest_scoring_system) + chatter_interest_scoring_system.relationship_tracker = relationship_tracker logger.info("回复后关系追踪系统初始化成功") - else: - logger.warning("回复后关系追踪系统初始化失败") + except Exception as e: + logger.error(f"回复后关系追踪系统初始化失败: {e}") + relationship_tracker = None # 启动情绪管理器 await mood_manager.start() diff --git a/src/plugin_system/base/base_chatter.py b/src/plugin_system/base/base_chatter.py index 3f46b0c3a..27224a5d2 100644 --- a/src/plugin_system/base/base_chatter.py +++ b/src/plugin_system/base/base_chatter.py @@ -5,8 +5,8 @@ from .component_types import ChatType from src.plugin_system.base.component_types import ChatterInfo, ComponentType if TYPE_CHECKING: - from src.chat.planner_actions.action_manager import ActionManager - from src.chat.planner_actions.planner import ActionPlanner + from src.chat.planner_actions.action_manager import ChatterActionManager + from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner class BaseChatter(ABC): chatter_name: str = "" @@ -15,7 +15,7 @@ class BaseChatter(ABC): """Chatter组件的描述""" chat_types: List[ChatType] = [ChatType.PRIVATE, ChatType.GROUP] - def __init__(self, stream_id: str, planner: 'ActionPlanner', action_manager: 'ActionManager'): + def __init__(self, stream_id: str, planner: 'ActionPlanner', action_manager: 'ChatterActionManager'): """ 初始化聊天处理器 diff --git a/src/plugins/built_in/chatter/README.md b/src/plugins/built_in/affinity_flow_chatter/README.md similarity index 96% rename from src/plugins/built_in/chatter/README.md rename to src/plugins/built_in/affinity_flow_chatter/README.md index d965d8215..26add6a34 100644 --- a/src/plugins/built_in/chatter/README.md +++ b/src/plugins/built_in/affinity_flow_chatter/README.md @@ -34,10 +34,10 @@ ```python from src.chat.chatter_manager import ChatterManager -from src.chat.planner_actions.action_manager import ActionManager +from src.chat.planner_actions.action_manager import ChatterActionManager # 初始化 -action_manager = ActionManager() +action_manager = ChatterActionManager() chatter_manager = ChatterManager(action_manager) # 处理消息流 diff --git a/src/plugins/built_in/affinity_flow_chatter/__init__.py b/src/plugins/built_in/affinity_flow_chatter/__init__.py new file mode 100644 index 000000000..b41def533 --- /dev/null +++ b/src/plugins/built_in/affinity_flow_chatter/__init__.py @@ -0,0 +1,7 @@ +""" +亲和力聊天处理器插件 +""" + +from .plugin import AffinityChatterPlugin + +__all__ = ["AffinityChatterPlugin"] \ No newline at end of file diff --git a/src/plugins/built_in/chatter/_manifest.json b/src/plugins/built_in/affinity_flow_chatter/_manifest.json similarity index 100% rename from src/plugins/built_in/chatter/_manifest.json rename to src/plugins/built_in/affinity_flow_chatter/_manifest.json diff --git a/src/plugins/built_in/chatter/affinity_chatter.py b/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py similarity index 97% rename from src/plugins/built_in/chatter/affinity_chatter.py rename to src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py index 12eb7e016..e0c26f6c9 100644 --- a/src/plugins/built_in/chatter/affinity_chatter.py +++ b/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py @@ -11,8 +11,8 @@ from typing import Dict, Any from src.plugin_system.base.base_chatter import BaseChatter from src.plugin_system.base.component_types import ChatType, ChatMode from src.common.data_models.message_manager_data_model import StreamContext -from src.chat.planner_actions.planner import ActionPlanner -from src.chat.planner_actions.action_manager import ActionManager +from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner +from src.chat.planner_actions.action_manager import ChatterActionManager from src.common.logger import get_logger logger = get_logger("affinity_chatter") @@ -24,7 +24,7 @@ class AffinityChatter(BaseChatter): chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型" chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型 - def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager): + def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ChatterActionManager): """ 初始化亲和力聊天处理器 diff --git a/src/chat/affinity_flow/interest_scoring.py b/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py similarity index 98% rename from src/chat/affinity_flow/interest_scoring.py rename to src/plugins/built_in/affinity_flow_chatter/interest_scoring.py index 2d2a8f72a..aab6978ce 100644 --- a/src/chat/affinity_flow/interest_scoring.py +++ b/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py @@ -13,10 +13,10 @@ from src.chat.interest_system import bot_interest_manager from src.common.logger import get_logger from src.config.config import global_config -logger = get_logger("interest_scoring") +logger = get_logger("chatter_interest_scoring") -class InterestScoringSystem: +class ChatterInterestScoringSystem: """兴趣度评分系统""" def __init__(self): @@ -230,9 +230,9 @@ class InterestScoringSystem: else: # 尝试从全局关系追踪器获取 try: - from src.chat.affinity_flow.relationship_integration import get_relationship_tracker + from .relationship_tracker import ChatterRelationshipTracker - global_tracker = get_relationship_tracker() + global_tracker = ChatterRelationshipTracker() if global_tracker: relationship_score = global_tracker.get_user_relationship_score(user_id) # 同时更新内存缓存 @@ -365,4 +365,4 @@ class InterestScoringSystem: # 创建全局兴趣评分系统实例 -interest_scoring_system = InterestScoringSystem() +chatter_interest_scoring_system = ChatterInterestScoringSystem() \ No newline at end of file diff --git a/src/chat/planner_actions/plan_executor.py b/src/plugins/built_in/affinity_flow_chatter/plan_executor.py similarity index 98% rename from src/chat/planner_actions/plan_executor.py rename to src/plugins/built_in/affinity_flow_chatter/plan_executor.py index 9c266b0ec..dba0db3e3 100644 --- a/src/chat/planner_actions/plan_executor.py +++ b/src/plugins/built_in/affinity_flow_chatter/plan_executor.py @@ -9,14 +9,14 @@ import time from typing import Dict, List from src.config.config import global_config -from src.chat.planner_actions.action_manager import ActionManager +from src.chat.planner_actions.action_manager import ChatterActionManager from src.common.data_models.info_data_model import Plan, ActionPlannerInfo from src.common.logger import get_logger logger = get_logger("plan_executor") -class PlanExecutor: +class ChatterPlanExecutor: """ 增强版PlanExecutor,集成用户关系追踪机制。 @@ -27,12 +27,12 @@ class PlanExecutor: 4. 提供完整的执行统计和监控 """ - def __init__(self, action_manager: ActionManager): + def __init__(self, action_manager: ChatterActionManager): """ 初始化增强版PlanExecutor。 Args: - action_manager (ActionManager): 用于实际执行各种动作的管理器实例。 + action_manager (ChatterActionManager): 用于实际执行各种动作的管理器实例。 """ self.action_manager = action_manager @@ -236,7 +236,7 @@ class PlanExecutor: logger.info(f"检测到戳一戳动作,目标用户: {user_name}") else: logger.warning("无法从戳一戳消息中获取用户ID或昵称。") - + # 传递原始消息ID以支持引用 action_data["target_message_id"] = target_message.get("message_id") @@ -360,4 +360,4 @@ class PlanExecutor: "timestamp": time.time() - (len(recent_times) - i) * 60, # 估算时间戳 } for i, time_val in enumerate(recent_times) - ] + ] \ No newline at end of file diff --git a/src/chat/planner_actions/plan_filter.py b/src/plugins/built_in/affinity_flow_chatter/plan_filter.py similarity index 99% rename from src/chat/planner_actions/plan_filter.py rename to src/plugins/built_in/affinity_flow_chatter/plan_filter.py index 3e731f368..13d54abd3 100644 --- a/src/chat/planner_actions/plan_filter.py +++ b/src/plugins/built_in/affinity_flow_chatter/plan_filter.py @@ -28,7 +28,7 @@ from src.schedule.schedule_manager import schedule_manager logger = get_logger("plan_filter") -class PlanFilter: +class ChatterPlanFilter: """ 根据 Plan 中的模式和信息,筛选并决定最终的动作。 """ @@ -321,7 +321,7 @@ class PlanFilter: interest_scores = {} try: - from src.chat.affinity_flow.interest_scoring import interest_scoring_system + from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system from src.common.data_models.database_data_model import DatabaseMessages # 转换消息格式 @@ -516,4 +516,4 @@ class PlanFilter: def _get_latest_message(self, message_id_list: list) -> Optional[Dict[str, Any]]: if not message_id_list: return None - return message_id_list[-1].get("message") + return message_id_list[-1].get("message") \ No newline at end of file diff --git a/src/plugins/built_in/affinity_flow_chatter/plan_generator.py b/src/plugins/built_in/affinity_flow_chatter/plan_generator.py new file mode 100644 index 000000000..c29116887 --- /dev/null +++ b/src/plugins/built_in/affinity_flow_chatter/plan_generator.py @@ -0,0 +1,167 @@ +""" +PlanGenerator: 负责搜集和汇总所有决策所需的信息,生成一个未经筛选的"原始计划" (Plan)。 +""" + +import time +from typing import Dict + +from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat +from src.chat.utils.utils import get_chat_type_and_target_info +from src.common.data_models.database_data_model import DatabaseMessages +from src.common.data_models.info_data_model import Plan, TargetPersonInfo +from src.config.config import global_config +from src.plugin_system.base.component_types import ActionActivationType, ActionInfo, ChatMode, ChatType, ComponentType +from src.plugin_system.core.component_registry import component_registry + + +class ChatterPlanGenerator: + """ + ChatterPlanGenerator 负责在规划流程的初始阶段收集所有必要信息。 + + 它会汇总以下信息来构建一个"原始"的 Plan 对象,该对象后续会由 PlanFilter 进行筛选: + - 当前聊天信息 (ID, 目标用户) + - 当前可用的动作列表 + - 最近的聊天历史记录 + + Attributes: + chat_id (str): 当前聊天的唯一标识符。 + action_manager (ActionManager): 用于获取可用动作列表的管理器。 + """ + + def __init__(self, chat_id: str): + """ + 初始化 ChatterPlanGenerator。 + + Args: + chat_id (str): 当前聊天的 ID。 + """ + from src.chat.planner_actions.action_manager import ChatterActionManager + + self.chat_id = chat_id + # 注意:ChatterActionManager 可能需要根据实际情况初始化 + self.action_manager = ChatterActionManager() + + async def generate(self, mode: ChatMode) -> Plan: + """ + 收集所有信息,生成并返回一个初始的 Plan 对象。 + + 这个 Plan 对象包含了决策所需的所有上下文信息。 + + Args: + mode (ChatMode): 当前的聊天模式。 + + Returns: + Plan: 包含所有上下文信息的初始计划对象。 + """ + try: + # 获取聊天类型和目标信息 + chat_type, target_info = get_chat_type_and_target_info(self.chat_id) + + # 获取可用动作列表 + available_actions = await self._get_available_actions(chat_type, mode) + + # 获取聊天历史记录 + recent_messages = await self._get_recent_messages() + + # 构建计划对象 + plan = Plan( + chat_id=self.chat_id, + mode=mode, + target_info=target_info, + available_actions=available_actions, + chat_history=recent_messages, + ) + + return plan + + except Exception as e: + # 如果生成失败,返回一个基本的空计划 + return Plan( + chat_id=self.chat_id, + mode=mode, + target_info=TargetPersonInfo(), + available_actions={}, + chat_history=[], + ) + + async def _get_available_actions(self, chat_type: ChatType, mode: ChatMode) -> Dict[str, ActionInfo]: + """ + 获取当前可用的动作列表。 + + Args: + chat_type (ChatType): 聊天类型。 + mode (ChatMode): 聊天模式。 + + Returns: + Dict[str, ActionInfo]: 可用动作的字典。 + """ + try: + # 从组件注册表获取可用动作 + available_actions = component_registry.get_enabled_actions() + + # 根据聊天类型和模式筛选动作 + filtered_actions = {} + for action_name, action_info in available_actions.items(): + # 检查动作是否支持当前聊天类型 + if chat_type in action_info.chat_types: + # 检查动作是否支持当前模式 + if mode in action_info.chat_modes: + filtered_actions[action_name] = action_info + + return filtered_actions + + except Exception as e: + # 如果获取失败,返回空字典 + return {} + + async def _get_recent_messages(self) -> list[DatabaseMessages]: + """ + 获取最近的聊天历史记录。 + + Returns: + list[DatabaseMessages]: 最近的聊天消息列表。 + """ + try: + # 获取最近的消息记录 + raw_messages = get_raw_msg_before_timestamp_with_chat( + chat_id=self.chat_id, + timestamp=time.time(), + limit=global_config.memory.short_memory_length + ) + + # 转换为 DatabaseMessages 对象 + recent_messages = [] + for msg in raw_messages: + try: + db_msg = DatabaseMessages( + message_id=msg.get("message_id", ""), + time=float(msg.get("time", 0)), + chat_id=msg.get("chat_id", ""), + processed_plain_text=msg.get("processed_plain_text", ""), + user_id=msg.get("user_id", ""), + user_nickname=msg.get("user_nickname", ""), + user_platform=msg.get("user_platform", ""), + ) + recent_messages.append(db_msg) + except Exception as e: + # 跳过格式错误的消息 + continue + + return recent_messages + + except Exception as e: + # 如果获取失败,返回空列表 + return [] + + def get_generator_stats(self) -> Dict: + """ + 获取生成器统计信息。 + + Returns: + Dict: 统计信息字典。 + """ + return { + "chat_id": self.chat_id, + "action_count": len(self.action_manager._using_actions) if hasattr(self.action_manager, '_using_actions') else 0, + "generation_time": time.time() + } \ No newline at end of file diff --git a/src/chat/planner_actions/planner.py b/src/plugins/built_in/affinity_flow_chatter/planner.py similarity index 83% rename from src/chat/planner_actions/planner.py rename to src/plugins/built_in/affinity_flow_chatter/planner.py index 9c4013a83..777cf18c7 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/plugins/built_in/affinity_flow_chatter/planner.py @@ -7,28 +7,28 @@ from dataclasses import asdict from typing import TYPE_CHECKING, Dict, List, Optional, Tuple from src.plugin_system.base.component_types import ChatMode -from src.chat.planner_actions.plan_executor import PlanExecutor -from src.chat.planner_actions.plan_filter import PlanFilter -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.plugins.built_in.chatter.plan_executor import ChatterPlanExecutor +from src.plugins.built_in.chatter.plan_filter import ChatterPlanFilter +from src.plugins.built_in.chatter.plan_generator import ChatterPlanGenerator +from src.plugins.built_in.chatter.interest_scoring import ChatterInterestScoringSystem +from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker from src.common.logger import get_logger from src.config.config import global_config if TYPE_CHECKING: - from src.chat.planner_actions.action_manager import ActionManager from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.info_data_model import Plan - + from src.chat.planner_actions.action_manager import ChatterActionManager + # 导入提示词模块以确保其被初始化 -from src.chat.planner_actions import planner_prompts # noqa +from src.plugins.built_in.chatter import planner_prompts # noqa logger = get_logger("planner") -class ActionPlanner: +class ChatterActionPlanner: """ 增强版ActionPlanner,集成兴趣度评分和用户关系追踪机制。 @@ -39,42 +39,26 @@ class ActionPlanner: 4. 完整的规划流程:生成→筛选→执行的完整三阶段流程 """ - def __init__(self, chat_id: str, action_manager: "ActionManager"): + def __init__(self, chat_id: str, action_manager: "ChatterActionManager"): """ 初始化增强版ActionPlanner。 Args: chat_id (str): 当前聊天的 ID。 - action_manager (ActionManager): 一个 ActionManager 实例。 + action_manager (ChatterActionManager): 一个 ChatterActionManager 实例。 """ self.chat_id = chat_id self.action_manager = action_manager - self.generator = PlanGenerator(chat_id) - self.filter = PlanFilter() - self.executor = PlanExecutor(action_manager) + self.generator = ChatterPlanGenerator(chat_id) + self.filter = ChatterPlanFilter() + self.executor = ChatterPlanExecutor(action_manager) # 初始化兴趣度评分系统 - self.interest_scoring = InterestScoringSystem() + self.interest_scoring = ChatterInterestScoringSystem() - # 尝试获取全局关系追踪器,如果没有则创建新的 - try: - from src.chat.affinity_flow.relationship_integration import get_relationship_tracker - - global_relationship_tracker = get_relationship_tracker() - if global_relationship_tracker: - # 使用全局关系追踪器 - self.relationship_tracker = global_relationship_tracker - # 设置兴趣度评分系统的关系追踪器引用 - self.interest_scoring.relationship_tracker = self.relationship_tracker - logger.info("使用全局关系追踪器") - else: - # 创建新的关系追踪器 - self.relationship_tracker = UserRelationshipTracker(self.interest_scoring) - logger.info("创建新的关系追踪器实例") - except Exception as e: - logger.warning(f"获取全局关系追踪器失败: {e}") - # 创建新的关系追踪器 - self.relationship_tracker = UserRelationshipTracker(self.interest_scoring) + # 创建新的关系追踪器 + self.relationship_tracker = ChatterRelationshipTracker(self.interest_scoring) + logger.info("创建新的关系追踪器实例") # 设置执行器的关系追踪器 self.executor.set_relationship_tracker(self.relationship_tracker) @@ -257,4 +241,4 @@ class ActionPlanner: } -# 全局兴趣度评分系统实例 - 在 individuality 模块中创建 +# 全局兴趣度评分系统实例 - 在 individuality 模块中创建 \ No newline at end of file diff --git a/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py b/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py new file mode 100644 index 000000000..15dcb584b --- /dev/null +++ b/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py @@ -0,0 +1,260 @@ +""" +本文件集中管理所有与规划器(Planner)相关的提示词(Prompt)模板。 + +通过将提示词与代码逻辑分离,可以更方便地对模型的行为进行迭代和优化, +而无需修改核心代码。 +""" + +from src.chat.utils.prompt import Prompt + + +def init_prompts(): + """ + 初始化并向 Prompt 注册系统注册所有规划器相关的提示词。 + + 这个函数会在模块加载时自动调用,确保所有提示词在系统启动时都已准备就绪。 + """ + # 核心规划器提示词,用于在接收到新消息时决定如何回应。 + # 它构建了一个复杂的上下文,包括历史记录、可用动作、角色设定等, + # 并要求模型以 JSON 格式输出一个或多个动作组合。 + Prompt( + """ +{mood_block} +{time_block} +{identity_block} + +{users_in_chat} +{custom_prompt_block} +{chat_context_description},以下是具体的聊天内容。 + +## 📜 已读历史消息(仅供参考) +{read_history_block} + +## 📬 未读历史消息(动作执行对象) +{unread_history_block} + +{moderation_prompt} + +**任务: 构建一个完整的响应** +你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成: +1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。 +2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。 + +**决策流程:** +1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。** +2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。** +3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。 +4. 首先,决定是否要对未读消息进行 `reply`(如果有)。 +5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。 +6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。 +7. 如果用户明确要求了某个动作,请务必优先满足。 + +**动作限制:** +- 在私聊中,你只能使用 `reply` 动作。私聊中不允许使用任何其他动作。 +- 在群聊中,你可以自由选择是否使用辅助动作。 + +**重要提醒:** +- **回复消息时必须遵循对话的流程,不要重复已经说过的话。** +- **确保回复与上下文紧密相关,回应要针对用户的消息内容。** +- **保持角色设定的一致性,使用符合你性格的语言风格。** + +**输出格式:** +请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段: +```json +{{ + "thinking": "你的思考过程,分析当前情况并说明为什么选择这些动作", + "actions": [ + {{ + "action_type": "动作类型(如:reply, emoji等)", + "reasoning": "选择该动作的理由", + "action_data": {{ + "target_message_id": "目标消息ID", + "content": "回复内容或其他动作所需数据" + }} + }} + ] +}} +``` + +如果没有合适的回复对象或不需要回复,输出空的 actions 数组: +```json +{{ + "thinking": "说明为什么不需要回复", + "actions": [] +}} +``` +""", + "planner_prompt", + ) + + # 主动规划器提示词,用于主动场景和前瞻性规划 + Prompt( + """ +{mood_block} +{time_block} +{identity_block} + +{users_in_chat} +{custom_prompt_block} +{chat_context_description},以下是具体的聊天内容。 + +## 📜 已读历史消息(仅供参考) +{read_history_block} + +## 📬 未读历史消息(动作执行对象) +{unread_history_block} + +{moderation_prompt} + +**任务: 构建一个完整的响应** +你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成: +1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。 +2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。 + +**决策流程:** +1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。** +2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。** +3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。 +4. 首先,决定是否要对未读消息进行 `reply`(如果有)。 +5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。 +6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。 +7. 如果用户明确要求了某个动作,请务必优先满足。 + +**动作限制:** +- 在私聊中,你只能使用 `reply` 动作。私聊中不允许使用任何其他动作。 +- 在群聊中,你可以自由选择是否使用辅助动作。 + +**重要提醒:** +- **回复消息时必须遵循对话的流程,不要重复已经说过的话。** +- **确保回复与上下文紧密相关,回应要针对用户的消息内容。** +- **保持角色设定的一致性,使用符合你性格的语言风格。** + +**输出格式:** +请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段: +```json +{{ + "thinking": "你的思考过程,分析当前情况并说明为什么选择这些动作", + "actions": [ + {{ + "action_type": "动作类型(如:reply, emoji等)", + "reasoning": "选择该动作的理由", + "action_data": {{ + "target_message_id": "目标消息ID", + "content": "回复内容或其他动作所需数据" + }} + }} + ] +}} +``` + +如果没有合适的回复对象或不需要回复,输出空的 actions 数组: +```json +{{ + "thinking": "说明为什么不需要回复", + "actions": [] +}} +``` +""", + "proactive_planner_prompt", + ) + + # 轻量级规划器提示词,用于快速决策和简单场景 + Prompt( + """ +{identity_block} + +## 当前聊天情景 +{chat_context_description} + +## 未读消息 +{unread_history_block} + +**任务:快速决策** +请根据当前聊天内容,快速决定是否需要回复。 + +**决策规则:** +1. 如果有人直接提到你或问你问题,优先回复 +2. 如果消息内容符合你的兴趣,考虑回复 +3. 如果只是群聊中的普通聊天且与你无关,可以不回复 + +**输出格式:** +```json +{{ + "thinking": "简要分析", + "actions": [ + {{ + "action_type": "reply", + "reasoning": "回复理由", + "action_data": {{ + "target_message_id": "目标消息ID", + "content": "回复内容" + }} + }} + ] +}} +``` +""", + "chatter_planner_lite", + ) + + # 动作筛选器提示词,用于筛选和优化规划器生成的动作 + Prompt( + """ +{identity_block} + +## 原始动作计划 +{original_plan} + +## 聊天上下文 +{chat_context} + +**任务:动作筛选优化** +请对原始动作计划进行筛选和优化,确保动作的合理性和有效性。 + +**筛选原则:** +1. 移除重复或不必要的动作 +2. 确保动作之间的逻辑顺序 +3. 优化动作的具体参数 +4. 考虑当前聊天环境和个人设定 + +**输出格式:** +```json +{{ + "thinking": "筛选优化思考", + "actions": [ + {{ + "action_type": "优化后的动作类型", + "reasoning": "优化理由", + "action_data": {{ + "target_message_id": "目标消息ID", + "content": "优化后的内容" + }} + }} + ] +}} +``` +""", + "chatter_plan_filter", + ) + + # 动作提示词,用于格式化动作选项 + Prompt( + """ +## 动作: {action_name} +**描述**: {action_description} + +**参数**: +{action_parameters} + +**要求**: +{action_require} + +**使用说明**: +请根据上述信息判断是否需要使用此动作。 +""", + "action_prompt", + ) + + +# 确保提示词在模块加载时初始化 +init_prompts() \ No newline at end of file diff --git a/src/plugins/built_in/chatter/plugin.py b/src/plugins/built_in/affinity_flow_chatter/plugin.py similarity index 100% rename from src/plugins/built_in/chatter/plugin.py rename to src/plugins/built_in/affinity_flow_chatter/plugin.py diff --git a/src/chat/affinity_flow/relationship_tracker.py b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py similarity index 99% rename from src/chat/affinity_flow/relationship_tracker.py rename to src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py index 49074bf93..5759b6c50 100644 --- a/src/chat/affinity_flow/relationship_tracker.py +++ b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py @@ -15,10 +15,10 @@ from src.common.database.sqlalchemy_models import UserRelationships, Messages from sqlalchemy import select, desc from src.common.data_models.database_data_model import DatabaseMessages -logger = get_logger("relationship_tracker") +logger = get_logger("chatter_relationship_tracker") -class UserRelationshipTracker: +class ChatterRelationshipTracker: """用户关系追踪器""" def __init__(self, interest_scoring_system=None): @@ -680,4 +680,4 @@ class UserRelationshipTracker: except Exception as e: logger.warning(f"清理LLM响应失败: {e}") - return response # 清理失败时返回原始响应 + return response # 清理失败时返回原始响应 \ No newline at end of file diff --git a/src/plugins/built_in/chatter/__init__.py b/src/plugins/built_in/chatter/__init__.py deleted file mode 100644 index c1c657070..000000000 --- a/src/plugins/built_in/chatter/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -亲和力聊天处理器插件 -""" - -from .plugin import AffinityChatterPlugin -from .affinity_chatter import AffinityChatter - -__all__ = ["AffinityChatterPlugin", "AffinityChatter"] \ No newline at end of file diff --git a/消息处理流程.md b/消息处理流程.md deleted file mode 100644 index db78ba7c1..000000000 --- a/消息处理流程.md +++ /dev/null @@ -1,235 +0,0 @@ -# 从消息接收到执行Action的完整流程图 - -## 整体流程概览 - -```mermaid -flowchart TD - A[原始消息数据] --> B[消息接收层
src/chat/message_receive/bot.py] - B --> C[消息解析
src/chat/message_receive/message.py] - C --> D[会话管理
src/chat/message_receive/chat_stream.py] - D --> E[亲和力流分发
src/chat/affinity_flow/afc_manager.py] - E --> F[聊天处理器
src/chat/affinity_flow/chatter.py] - F --> G[智能规划决策
三层架构] - G --> H[动作执行管理
src/chat/planner_actions/action_manager.py] - H --> I[最终执行
src/chat/planner_actions/plan_executor.py] - I --> J[Action执行结果] -``` - -## 详细分阶段流程图 - -### 1. 消息接收与预处理阶段 - -```mermaid -flowchart TD - A[原始消息数据] --> B[message_process入口] - B --> C{消息切片重组} - C -- 完整消息 --> D[平台类型判断] - C -- 切片消息 --> E[等待更多切片] - - D --> F{S4U平台?} - F -- 是 --> G[S4U特殊处理] - F -- 否 --> H[创建MessageRecv对象] - - H --> I[过滤检查
违禁词/正则] - I --> J[命令处理系统] - - J --> K{PlusCommand?} - K -- 是 --> L[执行PlusCommand] - K -- 否 --> M[执行BaseCommand] - - L --> N[事件触发] - M --> N - - N --> O[模板处理] - O --> P[预处理完成] -``` - -### 2. 消息解析阶段 - -```mermaid -flowchart TD - A[预处理完成消息] --> B[MessageRecv.process] - B --> C{消息类型判断} - - C -- 文本 --> D[直接提取文本] - C -- 图片 --> E[图片识别处理] - C -- 表情 --> F[表情包描述] - C -- 语音 --> G[语音转文本] - C -- 视频 --> H[视频内容分析] - C -- AT消息 --> I[提取用户信息] - C -- 其他 --> J[通用处理] - - D --> K[生成纯文本] - E --> K - F --> K - G --> K - H --> K - I --> K - J --> K - - K --> L[消息解析完成] -``` - -### 3. 会话管理阶段 - -```mermaid -flowchart TD - A[解析后消息] --> B[ChatManager.register_message] - B --> C[生成stream_id
platform+user+group] - - C --> D{会话是否存在?} - D -- 内存中存在 --> E[获取现有会话] - D -- 内存中不存在 --> F[数据库查询] - - F --> G{数据库存在?} - G -- 是 --> H[从数据库加载] - G -- 否 --> I[创建新会话] - - H --> J[更新会话信息] - I --> J - - J --> K[设置消息上下文] - K --> L[会话管理完成] -``` - -### 4. 智能规划决策阶段(三层架构) - -```mermaid -flowchart TD - A[会话管理完成] --> B[规划器入口 ActionPlanner] - - B --> C[PlanGenerator生成初始Plan] - C --> D[兴趣度评分系统] - - D --> E[提取未读消息] - E --> F[计算多维评分] - F --> G[兴趣匹配度] - F --> H[用户关系分] - F --> I[提及度评分] - - G --> J[加权总分计算] - H --> J - I --> J - - J --> K{是否回复?} - K -- 是 --> L[保留reply动作] - K -- 否 --> M[移除reply动作] - - L --> N[PlanFilter筛选] - M --> N - - N --> O[LLM决策最终动作] - O --> P[规划决策完成] -``` - -### 5. 动作执行阶段 - -```mermaid -flowchart TD - A[规划决策完成] --> B[ActionManager执行] - - B --> C{动作类型判断} - C -- no_action --> D[记录不动作] - C -- no_reply --> E[记录不回复] - C -- reply --> F[生成回复内容] - C -- 其他动作 --> G[执行具体动作] - - D --> H[执行完成] - E --> H - F --> I[发送回复消息] - G --> J[动作处理器执行] - - I --> H - J --> H - - H --> K[PlanExecutor最终执行] - K --> L[用户关系追踪] - L --> M[执行统计记录] - M --> N[动作执行完成] -``` - -## 完整端到端流程 - -```mermaid -flowchart LR - A[消息接收] --> B[消息解析] - B --> C[会话管理] - C --> D[消息分发] - D --> E[聊天处理] - E --> F[兴趣度评分] - F --> G[规划生成] - G --> H[LLM筛选] - H --> I[动作管理] - I --> J[最终执行] - J --> K[结果返回] - - subgraph 智能决策层 - F - G - H - end - - subgraph 执行层 - I - J - K - end - - style 智能决策层 fill:#e1f5fe - style 执行层 fill:#f3e5f5 -``` - -## 关键组件交互关系 - -```mermaid -flowchart TD - Bot[Bot.message_process] --> Message[MessageRecv] - Message --> ChatManager[ChatManager] - ChatManager --> AFCManager[AFCManager] - AFCManager --> Chatter[AffinityFlowChatter] - - Chatter --> Planner[ActionPlanner] - Planner --> Generator[PlanGenerator] - Planner --> Scorer[InterestScoringSystem] - Planner --> Filter[PlanFilter] - - Filter --> ActionManager[ActionManager] - ActionManager --> Executor[PlanExecutor] - - Executor --> Result[执行结果] - - %% 数据流 - Message -.-> |消息数据| Chatter - Scorer -.-> |兴趣评分| Filter - Generator -.-> |初始Plan| Filter - Filter -.-> |最终Plan| Executor -``` - -## 异常处理流程 - -```mermaid -flowchart TD - A[开始处理] --> B[正常流程] - B --> C[处理完成] - - B --> D{发生异常?} - D -- 是 --> E[异常捕获] - D -- 否 --> C - - E --> F[日志记录错误] - F --> G[错误类型判断] - - G -- 消息解析失败 --> H[返回解析错误] - G -- 会话不存在 --> I[创建新会话重试] - G -- LLM决策失败 --> J[使用默认动作] - G -- 动作执行失败 --> K[动作回退机制] - G -- 其他错误 --> L[返回通用错误] - - H --> M[异常处理完成] - I --> B - J --> M - K --> M - L --> M -``` - -这个流程图详细展示了从消息接收到执行action的完整流程,包括各个阶段的处理逻辑、组件交互关系以及异常处理机制。整个系统采用了模块化设计,具有清晰的职责分离和良好的可扩展性。 \ No newline at end of file