refactor(chat): 移除亲和力流模块并将其重构为插件架构
BREAKING CHANGE: 原有的亲和力流相关模块(src/chat/affinity_flow/)已被完全移除,相关功能已重构为插件形式。需要更新配置文件和相关依赖。 - 删除 src/chat/affinity_flow/ 目录下的所有文件 - 将 AFC 管理器功能移至 chatter 插件中实现 - 更新相关导入路径和引用 - 重构关系追踪器和兴趣评分系统的初始化逻辑 - 调整聊天管理器和消息管理器以适应新的插件架构
This commit is contained in:
@@ -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"]
|
||||
@@ -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()
|
||||
@@ -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)})"
|
||||
)
|
||||
@@ -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()
|
||||
@@ -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] = {}
|
||||
|
||||
@@ -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("频率触发器任务被取消。")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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": "根据我将要回复的文本内容,选择一个最匹配的表情包来增强表达效果。回复的文本是:<TEXT>"
|
||||
}}
|
||||
]
|
||||
|
||||
**重要规则:**
|
||||
1. 当 `reply` 和 `emoji` 动作同时被选择时,`emoji` 动作的 `reason` 字段必须包含 `reply` 动作最终生成的回复文本内容。你需要将 `<TEXT>` 占位符替换为 `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()
|
||||
@@ -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"])
|
||||
|
||||
@@ -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(
|
||||
|
||||
13
src/main.py
13
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()
|
||||
|
||||
@@ -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'):
|
||||
"""
|
||||
初始化聊天处理器
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
# 处理消息流
|
||||
7
src/plugins/built_in/affinity_flow_chatter/__init__.py
Normal file
7
src/plugins/built_in/affinity_flow_chatter/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
"""
|
||||
亲和力聊天处理器插件
|
||||
"""
|
||||
|
||||
from .plugin import AffinityChatterPlugin
|
||||
|
||||
__all__ = ["AffinityChatterPlugin"]
|
||||
@@ -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):
|
||||
"""
|
||||
初始化亲和力聊天处理器
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
]
|
||||
]
|
||||
@@ -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")
|
||||
167
src/plugins/built_in/affinity_flow_chatter/plan_generator.py
Normal file
167
src/plugins/built_in/affinity_flow_chatter/plan_generator.py
Normal file
@@ -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()
|
||||
}
|
||||
@@ -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 模块中创建
|
||||
260
src/plugins/built_in/affinity_flow_chatter/planner_prompts.py
Normal file
260
src/plugins/built_in/affinity_flow_chatter/planner_prompts.py
Normal file
@@ -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()
|
||||
@@ -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 # 清理失败时返回原始响应
|
||||
@@ -1,8 +0,0 @@
|
||||
"""
|
||||
亲和力聊天处理器插件
|
||||
"""
|
||||
|
||||
from .plugin import AffinityChatterPlugin
|
||||
from .affinity_chatter import AffinityChatter
|
||||
|
||||
__all__ = ["AffinityChatterPlugin", "AffinityChatter"]
|
||||
Reference in New Issue
Block a user