feat: 在插件系统中添加 Chatter 组件
- 在 component_types.py 中新增了用于 CHATTER 的 ComponentType。 - 实现了 ChatterInfo 类,用于存储 Chatter 组件的相关信息。 - 增强了 ComponentRegistry,以支持 Chatter 组件的注册与管理。 - 创建了 ChatterManager,用于管理 Chatter 实例并处理聊天流。 - 开发了 BaseChatter 抽象类,用于定义 Chatter 的行为规范。 - 实现了 AffinityChatter,作为具备兴趣评分与关系构建功能的具体 Chatter 组件。 - 添加了一个内置的 Chatter 插件,并附带完整文档与使用示例。 - 更新了 PluginManager,在插件概览中加入 Chatter 组件的统计信息。
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
提供全局的AFC管理器实例
|
提供全局的AFC管理器实例
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from src.chat.affinity_flow.afc_manager import afc_manager
|
# 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"]
|
__all__ = ["afc_manager", "AFCManager", "AffinityFlowChatter"]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from typing import Dict
|
|||||||
from src.chat.planner_actions.action_manager import ActionManager
|
from src.chat.planner_actions.action_manager import ActionManager
|
||||||
from src.chat.planner_actions.planner import ActionPlanner
|
from src.chat.planner_actions.planner import ActionPlanner
|
||||||
from src.common.data_models.message_manager_data_model import StreamContext
|
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.plugin_system.base.component_types import ChatMode
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
@@ -18,7 +19,7 @@ from src.common.logger import get_logger
|
|||||||
logger = get_logger("affinity_chatter")
|
logger = get_logger("affinity_chatter")
|
||||||
|
|
||||||
|
|
||||||
class AffinityFlowChatter:
|
class AffinityFlowChatter(BaseChatter):
|
||||||
"""单个亲和力聊天处理器"""
|
"""单个亲和力聊天处理器"""
|
||||||
|
|
||||||
def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager):
|
def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager):
|
||||||
@@ -44,7 +45,7 @@ class AffinityFlowChatter:
|
|||||||
}
|
}
|
||||||
self.last_activity_time = time.time()
|
self.last_activity_time = time.time()
|
||||||
|
|
||||||
async def process_stream_context(self, context: StreamContext) -> Dict[str, any]:
|
async def execute(self, context: StreamContext) -> dict:
|
||||||
"""
|
"""
|
||||||
处理StreamContext对象
|
处理StreamContext对象
|
||||||
|
|
||||||
|
|||||||
136
src/chat/chatter_manager.py
Normal file
136
src/chat/chatter_manager.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
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.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):
|
||||||
|
self.action_manager = action_manager
|
||||||
|
self.chatter_classes: Dict[ChatType, List[type]] = {}
|
||||||
|
self.instances: Dict[str, BaseChatter] = {}
|
||||||
|
|
||||||
|
# 管理器统计
|
||||||
|
self.stats = {
|
||||||
|
"chatters_registered": 0,
|
||||||
|
"streams_processed": 0,
|
||||||
|
"successful_executions": 0,
|
||||||
|
"failed_executions": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _auto_register_from_component_registry(self):
|
||||||
|
"""从组件注册表自动注册已注册的chatter组件"""
|
||||||
|
try:
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
# 获取所有CHATTER类型的组件
|
||||||
|
chatter_components = component_registry.get_enabled_chatter_registry()
|
||||||
|
for chatter_name, chatter_class in chatter_components.items():
|
||||||
|
self.register_chatter(chatter_class)
|
||||||
|
logger.info(f"自动注册chatter组件: {chatter_name}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"自动注册chatter组件时发生错误: {e}")
|
||||||
|
|
||||||
|
def register_chatter(self, chatter_class: type):
|
||||||
|
"""注册聊天处理器类"""
|
||||||
|
for chat_type in chatter_class.chat_types:
|
||||||
|
if chat_type not in self.chatter_classes:
|
||||||
|
self.chatter_classes[chat_type] = []
|
||||||
|
self.chatter_classes[chat_type].append(chatter_class)
|
||||||
|
logger.info(f"注册聊天处理器 {chatter_class.__name__} 支持 {chat_type.value} 聊天类型")
|
||||||
|
|
||||||
|
self.stats["chatters_registered"] += 1
|
||||||
|
|
||||||
|
def get_chatter_class(self, chat_type: ChatType) -> Optional[type]:
|
||||||
|
"""获取指定聊天类型的聊天处理器类"""
|
||||||
|
if chat_type in self.chatter_classes:
|
||||||
|
return self.chatter_classes[chat_type][0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_supported_chat_types(self) -> List[ChatType]:
|
||||||
|
"""获取支持的聊天类型列表"""
|
||||||
|
return list(self.chatter_classes.keys())
|
||||||
|
|
||||||
|
def get_registered_chatters(self) -> Dict[ChatType, List[type]]:
|
||||||
|
"""获取已注册的聊天处理器"""
|
||||||
|
return self.chatter_classes.copy()
|
||||||
|
|
||||||
|
def get_stream_instance(self, stream_id: str) -> Optional[BaseChatter]:
|
||||||
|
"""获取指定流的聊天处理器实例"""
|
||||||
|
return self.instances.get(stream_id)
|
||||||
|
|
||||||
|
def cleanup_inactive_instances(self, max_inactive_minutes: int = 60):
|
||||||
|
"""清理不活跃的实例"""
|
||||||
|
current_time = time.time()
|
||||||
|
max_inactive_seconds = max_inactive_minutes * 60
|
||||||
|
|
||||||
|
inactive_streams = []
|
||||||
|
for stream_id, instance in self.instances.items():
|
||||||
|
if hasattr(instance, 'get_activity_time'):
|
||||||
|
activity_time = instance.get_activity_time()
|
||||||
|
if (current_time - activity_time) > max_inactive_seconds:
|
||||||
|
inactive_streams.append(stream_id)
|
||||||
|
|
||||||
|
for stream_id in inactive_streams:
|
||||||
|
del self.instances[stream_id]
|
||||||
|
logger.info(f"清理不活跃聊天流实例: {stream_id}")
|
||||||
|
|
||||||
|
async def process_stream_context(self, stream_id: str, context: StreamContext) -> dict:
|
||||||
|
"""处理流上下文"""
|
||||||
|
chat_type = context.chat_type
|
||||||
|
logger.debug(f"处理流 {stream_id},聊天类型: {chat_type.value}")
|
||||||
|
if not self.chatter_classes:
|
||||||
|
self._auto_register_from_component_registry()
|
||||||
|
|
||||||
|
# 获取适合该聊天类型的chatter
|
||||||
|
chatter_class = self.get_chatter_class(chat_type)
|
||||||
|
if not chatter_class:
|
||||||
|
# 如果没有找到精确匹配,尝试查找支持ALL类型的chatter
|
||||||
|
from src.plugin_system.base.component_types import ChatType
|
||||||
|
all_chatter_class = self.get_chatter_class(ChatType.ALL)
|
||||||
|
if all_chatter_class:
|
||||||
|
chatter_class = all_chatter_class
|
||||||
|
logger.info(f"流 {stream_id} 使用通用chatter (类型: {chat_type.value})")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"No chatter registered for chat type {chat_type}")
|
||||||
|
|
||||||
|
if stream_id not in self.instances:
|
||||||
|
planner = ActionPlanner(stream_id, self.action_manager)
|
||||||
|
self.instances[stream_id] = chatter_class(stream_id=stream_id, planner=planner, action_manager=self.action_manager)
|
||||||
|
logger.info(f"创建新的聊天流实例: {stream_id} 使用 {chatter_class.__name__} (类型: {chat_type.value})")
|
||||||
|
|
||||||
|
self.stats["streams_processed"] += 1
|
||||||
|
try:
|
||||||
|
result = await self.instances[stream_id].execute(context)
|
||||||
|
self.stats["successful_executions"] += 1
|
||||||
|
|
||||||
|
# 记录处理结果
|
||||||
|
success = result.get("success", False)
|
||||||
|
actions_count = result.get("actions_count", 0)
|
||||||
|
logger.debug(f"流 {stream_id} 处理完成: 成功={success}, 动作数={actions_count}")
|
||||||
|
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
self.stats["failed_executions"] += 1
|
||||||
|
logger.error(f"处理流 {stream_id} 时发生错误: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def get_stats(self) -> Dict[str, Any]:
|
||||||
|
"""获取管理器统计信息"""
|
||||||
|
stats = self.stats.copy()
|
||||||
|
stats["active_instances"] = len(self.instances)
|
||||||
|
stats["registered_chatter_types"] = len(self.chatter_classes)
|
||||||
|
return stats
|
||||||
|
|
||||||
|
def reset_stats(self):
|
||||||
|
"""重置统计信息"""
|
||||||
|
self.stats = {
|
||||||
|
"chatters_registered": 0,
|
||||||
|
"streams_processed": 0,
|
||||||
|
"successful_executions": 0,
|
||||||
|
"failed_executions": 0,
|
||||||
|
}
|
||||||
@@ -11,7 +11,8 @@ from typing import Dict, Optional, Any, TYPE_CHECKING
|
|||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.common.data_models.database_data_model import DatabaseMessages
|
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.common.data_models.message_manager_data_model import StreamContext, MessageManagerStats, StreamStats
|
||||||
from src.chat.affinity_flow.afc_manager import afc_manager
|
from src.chat.chatter_manager import ChatterManager
|
||||||
|
from src.chat.planner_actions.action_manager import ActionManager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.common.data_models.message_manager_data_model import StreamContext
|
from src.common.data_models.message_manager_data_model import StreamContext
|
||||||
@@ -31,6 +32,10 @@ class MessageManager:
|
|||||||
# 统计信息
|
# 统计信息
|
||||||
self.stats = MessageManagerStats()
|
self.stats = MessageManagerStats()
|
||||||
|
|
||||||
|
# 初始化chatter manager
|
||||||
|
self.action_manager = ActionManager()
|
||||||
|
self.chatter_manager = ChatterManager(self.action_manager)
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
"""启动消息管理器"""
|
"""启动消息管理器"""
|
||||||
if self.is_running:
|
if self.is_running:
|
||||||
@@ -125,15 +130,23 @@ class MessageManager:
|
|||||||
# 直接使用StreamContext对象进行处理
|
# 直接使用StreamContext对象进行处理
|
||||||
if unread_messages:
|
if unread_messages:
|
||||||
try:
|
try:
|
||||||
# 发送到AFC处理器,传递StreamContext对象
|
# 记录当前chat type用于调试
|
||||||
results = await afc_manager.process_stream_context(stream_id, context)
|
logger.debug(f"聊天流 {stream_id} 检测到的chat type: {context.chat_type.value}")
|
||||||
|
|
||||||
|
# 发送到chatter manager,传递StreamContext对象
|
||||||
|
results = await self.chatter_manager.process_stream_context(stream_id, context)
|
||||||
|
|
||||||
# 处理结果,标记消息为已读
|
# 处理结果,标记消息为已读
|
||||||
if results.get("success", False):
|
if results.get("success", False):
|
||||||
self._clear_all_unread_messages(context)
|
self._clear_all_unread_messages(context)
|
||||||
|
logger.debug(f"聊天流 {stream_id} 处理成功,清除了 {len(unread_messages)} 条未读消息")
|
||||||
|
else:
|
||||||
|
logger.warning(f"聊天流 {stream_id} 处理失败: {results.get('error_message', '未知错误')}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"处理聊天流 {stream_id} 时发生异常,将清除所有未读消息: {e}")
|
logger.error(f"处理聊天流 {stream_id} 时发生异常,将清除所有未读消息: {e}")
|
||||||
|
# 出现异常时也清除未读消息,避免重复处理
|
||||||
|
self._clear_all_unread_messages(context)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
logger.debug(f"聊天流 {stream_id} 消息处理完成")
|
logger.debug(f"聊天流 {stream_id} 消息处理完成")
|
||||||
|
|||||||
@@ -4,20 +4,24 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from src.chat.planner_actions.action_manager import ActionManager
|
from src.plugin_system.base.component_types import ChatMode
|
||||||
from src.chat.planner_actions.plan_executor import PlanExecutor
|
from src.chat.planner_actions.plan_executor import PlanExecutor
|
||||||
from src.chat.planner_actions.plan_filter import PlanFilter
|
from src.chat.planner_actions.plan_filter import PlanFilter
|
||||||
from src.chat.planner_actions.plan_generator import PlanGenerator
|
from src.chat.planner_actions.plan_generator import PlanGenerator
|
||||||
from src.chat.affinity_flow.interest_scoring import InterestScoringSystem
|
from src.chat.affinity_flow.interest_scoring import InterestScoringSystem
|
||||||
from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker
|
from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker
|
||||||
from src.common.data_models.info_data_model import Plan
|
|
||||||
from src.common.data_models.message_manager_data_model import StreamContext
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.plugin_system.base.component_types import ChatMode
|
|
||||||
import src.chat.planner_actions.planner_prompts #noga # noqa: F401
|
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 import planner_prompts # noqa
|
from src.chat.planner_actions import planner_prompts # noqa
|
||||||
|
|
||||||
@@ -35,7 +39,7 @@ class ActionPlanner:
|
|||||||
4. 完整的规划流程:生成→筛选→执行的完整三阶段流程
|
4. 完整的规划流程:生成→筛选→执行的完整三阶段流程
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, chat_id: str, action_manager: ActionManager):
|
def __init__(self, chat_id: str, action_manager: "ActionManager"):
|
||||||
"""
|
"""
|
||||||
初始化增强版ActionPlanner。
|
初始化增强版ActionPlanner。
|
||||||
|
|
||||||
@@ -85,7 +89,7 @@ class ActionPlanner:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async def plan(
|
async def plan(
|
||||||
self, mode: ChatMode = ChatMode.FOCUS, context: StreamContext = None
|
self, mode: ChatMode = ChatMode.FOCUS, context: "StreamContext" = None
|
||||||
) -> Tuple[List[Dict], Optional[Dict]]:
|
) -> Tuple[List[Dict], Optional[Dict]]:
|
||||||
"""
|
"""
|
||||||
执行完整的增强版规划流程。
|
执行完整的增强版规划流程。
|
||||||
@@ -109,7 +113,7 @@ class ActionPlanner:
|
|||||||
self.planner_stats["failed_plans"] += 1
|
self.planner_stats["failed_plans"] += 1
|
||||||
return [], None
|
return [], None
|
||||||
|
|
||||||
async def _enhanced_plan_flow(self, mode: ChatMode, context: StreamContext) -> Tuple[List[Dict], Optional[Dict]]:
|
async def _enhanced_plan_flow(self, mode: ChatMode, context: "StreamContext") -> Tuple[List[Dict], Optional[Dict]]:
|
||||||
"""执行增强版规划流程"""
|
"""执行增强版规划流程"""
|
||||||
try:
|
try:
|
||||||
# 1. 生成初始 Plan
|
# 1. 生成初始 Plan
|
||||||
@@ -204,7 +208,7 @@ class ActionPlanner:
|
|||||||
self.planner_stats["replies_generated"] += reply_count
|
self.planner_stats["replies_generated"] += reply_count
|
||||||
self.planner_stats["other_actions_executed"] += other_count
|
self.planner_stats["other_actions_executed"] += other_count
|
||||||
|
|
||||||
def _build_return_result(self, plan: Plan) -> Tuple[List[Dict], Optional[Dict]]:
|
def _build_return_result(self, plan: "Plan") -> Tuple[List[Dict], Optional[Dict]]:
|
||||||
"""构建返回结果"""
|
"""构建返回结果"""
|
||||||
final_actions = plan.decided_actions or []
|
final_actions = plan.decided_actions or []
|
||||||
final_target_message = next((act.action_message for act in final_actions if act.action_message), None)
|
final_target_message = next((act.action_message for act in final_actions if act.action_message), None)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from enum import Enum
|
|||||||
from typing import List, Optional, TYPE_CHECKING
|
from typing import List, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from . import BaseDataModel
|
from . import BaseDataModel
|
||||||
|
from src.plugin_system.base.component_types import ChatType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .database_data_model import DatabaseMessages
|
from .database_data_model import DatabaseMessages
|
||||||
@@ -28,6 +29,7 @@ class StreamContext(BaseDataModel):
|
|||||||
"""聊天流上下文信息"""
|
"""聊天流上下文信息"""
|
||||||
|
|
||||||
stream_id: str
|
stream_id: str
|
||||||
|
chat_type: ChatType = ChatType.PRIVATE # 聊天类型,默认为私聊
|
||||||
unread_messages: List["DatabaseMessages"] = field(default_factory=list)
|
unread_messages: List["DatabaseMessages"] = field(default_factory=list)
|
||||||
history_messages: List["DatabaseMessages"] = field(default_factory=list)
|
history_messages: List["DatabaseMessages"] = field(default_factory=list)
|
||||||
last_check_time: float = field(default_factory=time.time)
|
last_check_time: float = field(default_factory=time.time)
|
||||||
@@ -39,6 +41,42 @@ class StreamContext(BaseDataModel):
|
|||||||
message.is_read = False
|
message.is_read = False
|
||||||
self.unread_messages.append(message)
|
self.unread_messages.append(message)
|
||||||
|
|
||||||
|
# 自动检测和更新chat type
|
||||||
|
self._detect_chat_type(message)
|
||||||
|
|
||||||
|
def _detect_chat_type(self, message: "DatabaseMessages"):
|
||||||
|
"""根据消息内容自动检测聊天类型"""
|
||||||
|
# 只有在第一次添加消息时才检测聊天类型,避免后续消息改变类型
|
||||||
|
if len(self.unread_messages) == 1: # 只有这条消息
|
||||||
|
# 如果消息包含群组信息,则为群聊
|
||||||
|
if hasattr(message, 'chat_info_group_id') and message.chat_info_group_id:
|
||||||
|
self.chat_type = ChatType.GROUP
|
||||||
|
elif hasattr(message, 'chat_info_group_name') and message.chat_info_group_name:
|
||||||
|
self.chat_type = ChatType.GROUP
|
||||||
|
else:
|
||||||
|
self.chat_type = ChatType.PRIVATE
|
||||||
|
|
||||||
|
def update_chat_type(self, chat_type: ChatType):
|
||||||
|
"""手动更新聊天类型"""
|
||||||
|
self.chat_type = chat_type
|
||||||
|
|
||||||
|
def is_group_chat(self) -> bool:
|
||||||
|
"""检查是否为群聊"""
|
||||||
|
return self.chat_type == ChatType.GROUP
|
||||||
|
|
||||||
|
def is_private_chat(self) -> bool:
|
||||||
|
"""检查是否为私聊"""
|
||||||
|
return self.chat_type == ChatType.PRIVATE
|
||||||
|
|
||||||
|
def get_chat_type_display(self) -> str:
|
||||||
|
"""获取聊天类型的显示名称"""
|
||||||
|
if self.chat_type == ChatType.GROUP:
|
||||||
|
return "群聊"
|
||||||
|
elif self.chat_type == ChatType.PRIVATE:
|
||||||
|
return "私聊"
|
||||||
|
else:
|
||||||
|
return "未知类型"
|
||||||
|
|
||||||
def get_unread_messages(self) -> List["DatabaseMessages"]:
|
def get_unread_messages(self) -> List["DatabaseMessages"]:
|
||||||
"""获取未读消息"""
|
"""获取未读消息"""
|
||||||
return [msg for msg in self.unread_messages if not msg.is_read]
|
return [msg for msg in self.unread_messages if not msg.is_read]
|
||||||
|
|||||||
57
src/plugin_system/base/base_chatter.py
Normal file
57
src/plugin_system/base/base_chatter.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import List, Optional, TYPE_CHECKING
|
||||||
|
from src.common.data_models.message_manager_data_model import StreamContext
|
||||||
|
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
|
||||||
|
|
||||||
|
class BaseChatter(ABC):
|
||||||
|
chatter_name: str = ""
|
||||||
|
"""Chatter组件的名称"""
|
||||||
|
chatter_description: str = ""
|
||||||
|
"""Chatter组件的描述"""
|
||||||
|
chat_types: List[ChatType] = [ChatType.PRIVATE, ChatType.GROUP]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def execute(self, context: StreamContext) -> dict:
|
||||||
|
"""
|
||||||
|
执行聊天处理流程
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context: StreamContext对象,包含聊天流的所有消息信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
处理结果字典
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_chatter_info(cls) -> "ChatterInfo":
|
||||||
|
"""从类属性生成ChatterInfo
|
||||||
|
Returns:
|
||||||
|
ChatterInfo对象
|
||||||
|
"""
|
||||||
|
|
||||||
|
return ChatterInfo(
|
||||||
|
name=cls.chatter_name,
|
||||||
|
description=cls.chatter_description or "No description provided.",
|
||||||
|
chat_type_allow=cls.chat_types[0],
|
||||||
|
component_type=ComponentType.CHATTER,
|
||||||
|
)
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ class ComponentType(Enum):
|
|||||||
TOOL = "tool" # 工具组件
|
TOOL = "tool" # 工具组件
|
||||||
SCHEDULER = "scheduler" # 定时任务组件(预留)
|
SCHEDULER = "scheduler" # 定时任务组件(预留)
|
||||||
EVENT_HANDLER = "event_handler" # 事件处理组件
|
EVENT_HANDLER = "event_handler" # 事件处理组件
|
||||||
|
CHATTER = "chatter" # 聊天处理器组件
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.value
|
return self.value
|
||||||
@@ -54,8 +55,8 @@ class ChatMode(Enum):
|
|||||||
class ChatType(Enum):
|
class ChatType(Enum):
|
||||||
"""聊天类型枚举,用于限制插件在不同聊天环境中的使用"""
|
"""聊天类型枚举,用于限制插件在不同聊天环境中的使用"""
|
||||||
|
|
||||||
GROUP = "group" # 仅群聊可用
|
|
||||||
PRIVATE = "private" # 仅私聊可用
|
PRIVATE = "private" # 仅私聊可用
|
||||||
|
GROUP = "group" # 仅群聊可用
|
||||||
ALL = "all" # 群聊和私聊都可用
|
ALL = "all" # 群聊和私聊都可用
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -210,6 +211,17 @@ class EventHandlerInfo(ComponentInfo):
|
|||||||
self.component_type = ComponentType.EVENT_HANDLER
|
self.component_type = ComponentType.EVENT_HANDLER
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ChatterInfo(ComponentInfo):
|
||||||
|
"""聊天处理器组件信息"""
|
||||||
|
|
||||||
|
chat_type_allow: ChatType = ChatType.ALL # 允许的聊天类型
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
super().__post_init__()
|
||||||
|
self.component_type = ComponentType.CHATTER
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EventInfo(ComponentInfo):
|
class EventInfo(ComponentInfo):
|
||||||
"""事件组件信息"""
|
"""事件组件信息"""
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from typing import Dict, List, Optional, Any, Pattern, Tuple, Union, Type
|
from typing import TYPE_CHECKING, Dict, List, Optional, Any, Pattern, Tuple, Union, Type
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.plugin_system.base.component_types import (
|
from src.plugin_system.base.component_types import (
|
||||||
@@ -11,14 +11,17 @@ from src.plugin_system.base.component_types import (
|
|||||||
CommandInfo,
|
CommandInfo,
|
||||||
PlusCommandInfo,
|
PlusCommandInfo,
|
||||||
EventHandlerInfo,
|
EventHandlerInfo,
|
||||||
|
ChatterInfo,
|
||||||
PluginInfo,
|
PluginInfo,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from src.plugin_system.base.base_command import BaseCommand
|
from src.plugin_system.base.base_command import BaseCommand
|
||||||
from src.plugin_system.base.base_action import BaseAction
|
from src.plugin_system.base.base_action import BaseAction
|
||||||
from src.plugin_system.base.base_tool import BaseTool
|
from src.plugin_system.base.base_tool import BaseTool
|
||||||
from src.plugin_system.base.base_events_handler import BaseEventHandler
|
from src.plugin_system.base.base_events_handler import BaseEventHandler
|
||||||
from src.plugin_system.base.plus_command import PlusCommand
|
from src.plugin_system.base.plus_command import PlusCommand
|
||||||
|
from src.plugin_system.base.base_chatter import BaseChatter
|
||||||
|
|
||||||
logger = get_logger("component_registry")
|
logger = get_logger("component_registry")
|
||||||
|
|
||||||
@@ -31,42 +34,45 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# 命名空间式组件名构成法 f"{component_type}.{component_name}"
|
# 命名空间式组件名构成法 f"{component_type}.{component_name}"
|
||||||
self._plus_command_registry: Dict[str, Type[PlusCommand]] = {}
|
self._components: Dict[str, 'ComponentInfo'] = {}
|
||||||
self._components: Dict[str, ComponentInfo] = {}
|
|
||||||
"""组件注册表 命名空间式组件名 -> 组件信息"""
|
"""组件注册表 命名空间式组件名 -> 组件信息"""
|
||||||
self._components_by_type: Dict[ComponentType, Dict[str, ComponentInfo]] = {types: {} for types in ComponentType}
|
self._components_by_type: Dict['ComponentType', Dict[str, 'ComponentInfo']] = {types: {} for types in ComponentType}
|
||||||
"""类型 -> 组件原名称 -> 组件信息"""
|
"""类型 -> 组件原名称 -> 组件信息"""
|
||||||
self._components_classes: Dict[
|
self._components_classes: Dict[
|
||||||
str, Type[Union[BaseCommand, BaseAction, BaseTool, BaseEventHandler, PlusCommand]]
|
str, Type[Union['BaseCommand', 'BaseAction', 'BaseTool', 'BaseEventHandler', 'PlusCommand', 'BaseChatter']]
|
||||||
] = {}
|
] = {}
|
||||||
"""命名空间式组件名 -> 组件类"""
|
"""命名空间式组件名 -> 组件类"""
|
||||||
|
|
||||||
# 插件注册表
|
# 插件注册表
|
||||||
self._plugins: Dict[str, PluginInfo] = {}
|
self._plugins: Dict[str, 'PluginInfo'] = {}
|
||||||
"""插件名 -> 插件信息"""
|
"""插件名 -> 插件信息"""
|
||||||
|
|
||||||
# Action特定注册表
|
# Action特定注册表
|
||||||
self._action_registry: Dict[str, Type[BaseAction]] = {}
|
self._action_registry: Dict[str, Type['BaseAction']] = {}
|
||||||
"""Action注册表 action名 -> action类"""
|
"""Action注册表 action名 -> action类"""
|
||||||
self._default_actions: Dict[str, ActionInfo] = {}
|
self._default_actions: Dict[str, 'ActionInfo'] = {}
|
||||||
"""默认动作集,即启用的Action集,用于重置ActionManager状态"""
|
"""默认动作集,即启用的Action集,用于重置ActionManager状态"""
|
||||||
|
|
||||||
# Command特定注册表
|
# Command特定注册表
|
||||||
self._command_registry: Dict[str, Type[BaseCommand]] = {}
|
self._command_registry: Dict[str, Type['BaseCommand']] = {}
|
||||||
"""Command类注册表 command名 -> command类"""
|
"""Command类注册表 command名 -> command类"""
|
||||||
self._command_patterns: Dict[Pattern, str] = {}
|
self._command_patterns: Dict[Pattern, str] = {}
|
||||||
"""编译后的正则 -> command名"""
|
"""编译后的正则 -> command名"""
|
||||||
|
|
||||||
# 工具特定注册表
|
# 工具特定注册表
|
||||||
self._tool_registry: Dict[str, Type[BaseTool]] = {} # 工具名 -> 工具类
|
self._tool_registry: Dict[str, Type['BaseTool']] = {} # 工具名 -> 工具类
|
||||||
self._llm_available_tools: Dict[str, Type[BaseTool]] = {} # llm可用的工具名 -> 工具类
|
self._llm_available_tools: Dict[str, Type['BaseTool']] = {} # llm可用的工具名 -> 工具类
|
||||||
|
|
||||||
# EventHandler特定注册表
|
# EventHandler特定注册表
|
||||||
self._event_handler_registry: Dict[str, Type[BaseEventHandler]] = {}
|
self._event_handler_registry: Dict[str, Type['BaseEventHandler']] = {}
|
||||||
"""event_handler名 -> event_handler类"""
|
"""event_handler名 -> event_handler类"""
|
||||||
self._enabled_event_handlers: Dict[str, Type[BaseEventHandler]] = {}
|
self._enabled_event_handlers: Dict[str, Type['BaseEventHandler']] = {}
|
||||||
"""启用的事件处理器 event_handler名 -> event_handler类"""
|
"""启用的事件处理器 event_handler名 -> event_handler类"""
|
||||||
|
|
||||||
|
self._chatter_registry: Dict[str, Type['BaseChatter']] = {}
|
||||||
|
"""chatter名 -> chatter类"""
|
||||||
|
self._enabled_chatter_registry: Dict[str, Type['BaseChatter']] = {}
|
||||||
|
"""启用的chatter名 -> chatter类"""
|
||||||
logger.info("组件注册中心初始化完成")
|
logger.info("组件注册中心初始化完成")
|
||||||
|
|
||||||
# == 注册方法 ==
|
# == 注册方法 ==
|
||||||
@@ -93,7 +99,7 @@ class ComponentRegistry:
|
|||||||
def register_component(
|
def register_component(
|
||||||
self,
|
self,
|
||||||
component_info: ComponentInfo,
|
component_info: ComponentInfo,
|
||||||
component_class: Type[Union[BaseCommand, BaseAction, BaseEventHandler, BaseTool]],
|
component_class: Type[Union['BaseCommand', 'BaseAction', 'BaseEventHandler', 'BaseTool', 'BaseChatter']],
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""注册组件
|
"""注册组件
|
||||||
|
|
||||||
@@ -151,6 +157,10 @@ class ComponentRegistry:
|
|||||||
assert isinstance(component_info, EventHandlerInfo)
|
assert isinstance(component_info, EventHandlerInfo)
|
||||||
assert issubclass(component_class, BaseEventHandler)
|
assert issubclass(component_class, BaseEventHandler)
|
||||||
ret = self._register_event_handler_component(component_info, component_class)
|
ret = self._register_event_handler_component(component_info, component_class)
|
||||||
|
case ComponentType.CHATTER:
|
||||||
|
assert isinstance(component_info, ChatterInfo)
|
||||||
|
assert issubclass(component_class, BaseChatter)
|
||||||
|
ret = self._register_chatter_component(component_info, component_class)
|
||||||
case _:
|
case _:
|
||||||
logger.warning(f"未知组件类型: {component_type}")
|
logger.warning(f"未知组件类型: {component_type}")
|
||||||
|
|
||||||
@@ -162,7 +172,7 @@ class ComponentRegistry:
|
|||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _register_action_component(self, action_info: ActionInfo, action_class: Type[BaseAction]) -> bool:
|
def _register_action_component(self, action_info: 'ActionInfo', action_class: Type['BaseAction']) -> bool:
|
||||||
"""注册Action组件到Action特定注册表"""
|
"""注册Action组件到Action特定注册表"""
|
||||||
if not (action_name := action_info.name):
|
if not (action_name := action_info.name):
|
||||||
logger.error(f"Action组件 {action_class.__name__} 必须指定名称")
|
logger.error(f"Action组件 {action_class.__name__} 必须指定名称")
|
||||||
@@ -182,7 +192,7 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _register_command_component(self, command_info: CommandInfo, command_class: Type[BaseCommand]) -> bool:
|
def _register_command_component(self, command_info: 'CommandInfo', command_class: Type['BaseCommand']) -> bool:
|
||||||
"""注册Command组件到Command特定注册表"""
|
"""注册Command组件到Command特定注册表"""
|
||||||
if not (command_name := command_info.name):
|
if not (command_name := command_info.name):
|
||||||
logger.error(f"Command组件 {command_class.__name__} 必须指定名称")
|
logger.error(f"Command组件 {command_class.__name__} 必须指定名称")
|
||||||
@@ -209,7 +219,7 @@ class ComponentRegistry:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _register_plus_command_component(
|
def _register_plus_command_component(
|
||||||
self, plus_command_info: PlusCommandInfo, plus_command_class: Type[PlusCommand]
|
self, plus_command_info: 'PlusCommandInfo', plus_command_class: Type['PlusCommand']
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""注册PlusCommand组件到特定注册表"""
|
"""注册PlusCommand组件到特定注册表"""
|
||||||
plus_command_name = plus_command_info.name
|
plus_command_name = plus_command_info.name
|
||||||
@@ -223,7 +233,7 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
# 创建专门的PlusCommand注册表(如果还没有)
|
# 创建专门的PlusCommand注册表(如果还没有)
|
||||||
if not hasattr(self, "_plus_command_registry"):
|
if not hasattr(self, "_plus_command_registry"):
|
||||||
self._plus_command_registry: Dict[str, Type[PlusCommand]] = {}
|
self._plus_command_registry: Dict[str, Type['PlusCommand']] = {}
|
||||||
|
|
||||||
plus_command_class.plugin_name = plus_command_info.plugin_name
|
plus_command_class.plugin_name = plus_command_info.plugin_name
|
||||||
# 设置插件配置
|
# 设置插件配置
|
||||||
@@ -233,7 +243,7 @@ class ComponentRegistry:
|
|||||||
logger.debug(f"已注册PlusCommand组件: {plus_command_name}")
|
logger.debug(f"已注册PlusCommand组件: {plus_command_name}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _register_tool_component(self, tool_info: ToolInfo, tool_class: Type[BaseTool]) -> bool:
|
def _register_tool_component(self, tool_info: 'ToolInfo', tool_class: Type['BaseTool']) -> bool:
|
||||||
"""注册Tool组件到Tool特定注册表"""
|
"""注册Tool组件到Tool特定注册表"""
|
||||||
tool_name = tool_info.name
|
tool_name = tool_info.name
|
||||||
|
|
||||||
@@ -249,7 +259,7 @@ class ComponentRegistry:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _register_event_handler_component(
|
def _register_event_handler_component(
|
||||||
self, handler_info: EventHandlerInfo, handler_class: Type[BaseEventHandler]
|
self, handler_info: 'EventHandlerInfo', handler_class: Type['BaseEventHandler']
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if not (handler_name := handler_info.name):
|
if not (handler_name := handler_info.name):
|
||||||
logger.error(f"EventHandler组件 {handler_class.__name__} 必须指定名称")
|
logger.error(f"EventHandler组件 {handler_class.__name__} 必须指定名称")
|
||||||
@@ -275,9 +285,34 @@ class ComponentRegistry:
|
|||||||
handler_class, self.get_plugin_config(handler_info.plugin_name) or {}
|
handler_class, self.get_plugin_config(handler_info.plugin_name) or {}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _register_chatter_component(self, chatter_info: 'ChatterInfo', chatter_class: Type['BaseChatter']) -> bool:
|
||||||
|
"""注册Chatter组件到Chatter特定注册表"""
|
||||||
|
chatter_name = chatter_info.name
|
||||||
|
|
||||||
|
if not chatter_name:
|
||||||
|
logger.error(f"Chatter组件 {chatter_class.__name__} 必须指定名称")
|
||||||
|
return False
|
||||||
|
if not isinstance(chatter_info, ChatterInfo) or not issubclass(chatter_class, BaseChatter):
|
||||||
|
logger.error(f"注册失败: {chatter_name} 不是有效的Chatter")
|
||||||
|
return False
|
||||||
|
|
||||||
|
chatter_class.plugin_name = chatter_info.plugin_name
|
||||||
|
# 设置插件配置
|
||||||
|
chatter_class.plugin_config = self.get_plugin_config(chatter_info.plugin_name) or {}
|
||||||
|
|
||||||
|
self._chatter_registry[chatter_name] = chatter_class
|
||||||
|
|
||||||
|
if not chatter_info.enabled:
|
||||||
|
logger.warning(f"Chatter组件 {chatter_name} 未启用")
|
||||||
|
return True # 未启用,但是也是注册成功
|
||||||
|
self._enabled_chatter_registry[chatter_name] = chatter_class
|
||||||
|
|
||||||
|
logger.debug(f"已注册Chatter组件: {chatter_name}")
|
||||||
|
return True
|
||||||
|
|
||||||
# === 组件移除相关 ===
|
# === 组件移除相关 ===
|
||||||
|
|
||||||
async def remove_component(self, component_name: str, component_type: ComponentType, plugin_name: str) -> bool:
|
async def remove_component(self, component_name: str, component_type: 'ComponentType', plugin_name: str) -> bool:
|
||||||
target_component_class = self.get_component_class(component_name, component_type)
|
target_component_class = self.get_component_class(component_name, component_type)
|
||||||
if not target_component_class:
|
if not target_component_class:
|
||||||
logger.warning(f"组件 {component_name} 未注册,无法移除")
|
logger.warning(f"组件 {component_name} 未注册,无法移除")
|
||||||
@@ -325,6 +360,12 @@ class ComponentRegistry:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"移除EventHandler事件订阅时出错: {e}")
|
logger.warning(f"移除EventHandler事件订阅时出错: {e}")
|
||||||
|
|
||||||
|
case ComponentType.CHATTER:
|
||||||
|
# 移除Chatter注册
|
||||||
|
if hasattr(self, '_chatter_registry'):
|
||||||
|
self._chatter_registry.pop(component_name, None)
|
||||||
|
logger.debug(f"已移除Chatter组件: {component_name}")
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
logger.warning(f"未知的组件类型: {component_type}")
|
logger.warning(f"未知的组件类型: {component_type}")
|
||||||
return False
|
return False
|
||||||
@@ -443,8 +484,8 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
# === 组件查询方法 ===
|
# === 组件查询方法 ===
|
||||||
def get_component_info(
|
def get_component_info(
|
||||||
self, component_name: str, component_type: Optional[ComponentType] = None
|
self, component_name: str, component_type: Optional['ComponentType'] = None
|
||||||
) -> Optional[ComponentInfo]:
|
) -> Optional['ComponentInfo']:
|
||||||
# sourcery skip: class-extract-method
|
# sourcery skip: class-extract-method
|
||||||
"""获取组件信息,支持自动命名空间解析
|
"""获取组件信息,支持自动命名空间解析
|
||||||
|
|
||||||
@@ -488,8 +529,8 @@ class ComponentRegistry:
|
|||||||
def get_component_class(
|
def get_component_class(
|
||||||
self,
|
self,
|
||||||
component_name: str,
|
component_name: str,
|
||||||
component_type: Optional[ComponentType] = None,
|
component_type: Optional['ComponentType'] = None,
|
||||||
) -> Optional[Union[Type[BaseCommand], Type[BaseAction], Type[BaseEventHandler], Type[BaseTool]]]:
|
) -> Optional[Union[Type['BaseCommand'], Type['BaseAction'], Type['BaseEventHandler'], Type['BaseTool']]]:
|
||||||
"""获取组件类,支持自动命名空间解析
|
"""获取组件类,支持自动命名空间解析
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -506,7 +547,7 @@ class ComponentRegistry:
|
|||||||
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
# 2. 如果指定了组件类型,构造命名空间化的名称查找
|
||||||
if component_type:
|
if component_type:
|
||||||
namespaced_name = f"{component_type.value}.{component_name}"
|
namespaced_name = f"{component_type.value}.{component_name}"
|
||||||
return self._components_classes.get(namespaced_name)
|
return self._components_classes.get(namespaced_name) # type: ignore[valid-type]
|
||||||
|
|
||||||
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
# 3. 如果没有指定类型,尝试在所有命名空间中查找
|
||||||
candidates = []
|
candidates = []
|
||||||
@@ -531,22 +572,22 @@ class ComponentRegistry:
|
|||||||
# 4. 都没找到
|
# 4. 都没找到
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_components_by_type(self, component_type: ComponentType) -> Dict[str, ComponentInfo]:
|
def get_components_by_type(self, component_type: 'ComponentType') -> Dict[str, 'ComponentInfo']:
|
||||||
"""获取指定类型的所有组件"""
|
"""获取指定类型的所有组件"""
|
||||||
return self._components_by_type.get(component_type, {}).copy()
|
return self._components_by_type.get(component_type, {}).copy()
|
||||||
|
|
||||||
def get_enabled_components_by_type(self, component_type: ComponentType) -> Dict[str, ComponentInfo]:
|
def get_enabled_components_by_type(self, component_type: 'ComponentType') -> Dict[str, 'ComponentInfo']:
|
||||||
"""获取指定类型的所有启用组件"""
|
"""获取指定类型的所有启用组件"""
|
||||||
components = self.get_components_by_type(component_type)
|
components = self.get_components_by_type(component_type)
|
||||||
return {name: info for name, info in components.items() if info.enabled}
|
return {name: info for name, info in components.items() if info.enabled}
|
||||||
|
|
||||||
# === Action特定查询方法 ===
|
# === Action特定查询方法 ===
|
||||||
|
|
||||||
def get_action_registry(self) -> Dict[str, Type[BaseAction]]:
|
def get_action_registry(self) -> Dict[str, Type['BaseAction']]:
|
||||||
"""获取Action注册表"""
|
"""获取Action注册表"""
|
||||||
return self._action_registry.copy()
|
return self._action_registry.copy()
|
||||||
|
|
||||||
def get_registered_action_info(self, action_name: str) -> Optional[ActionInfo]:
|
def get_registered_action_info(self, action_name: str) -> Optional['ActionInfo']:
|
||||||
"""获取Action信息"""
|
"""获取Action信息"""
|
||||||
info = self.get_component_info(action_name, ComponentType.ACTION)
|
info = self.get_component_info(action_name, ComponentType.ACTION)
|
||||||
return info if isinstance(info, ActionInfo) else None
|
return info if isinstance(info, ActionInfo) else None
|
||||||
@@ -557,11 +598,11 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
# === Command特定查询方法 ===
|
# === Command特定查询方法 ===
|
||||||
|
|
||||||
def get_command_registry(self) -> Dict[str, Type[BaseCommand]]:
|
def get_command_registry(self) -> Dict[str, Type['BaseCommand']]:
|
||||||
"""获取Command注册表"""
|
"""获取Command注册表"""
|
||||||
return self._command_registry.copy()
|
return self._command_registry.copy()
|
||||||
|
|
||||||
def get_registered_command_info(self, command_name: str) -> Optional[CommandInfo]:
|
def get_registered_command_info(self, command_name: str) -> Optional['CommandInfo']:
|
||||||
"""获取Command信息"""
|
"""获取Command信息"""
|
||||||
info = self.get_component_info(command_name, ComponentType.COMMAND)
|
info = self.get_component_info(command_name, ComponentType.COMMAND)
|
||||||
return info if isinstance(info, CommandInfo) else None
|
return info if isinstance(info, CommandInfo) else None
|
||||||
@@ -570,7 +611,7 @@ class ComponentRegistry:
|
|||||||
"""获取Command模式注册表"""
|
"""获取Command模式注册表"""
|
||||||
return self._command_patterns.copy()
|
return self._command_patterns.copy()
|
||||||
|
|
||||||
def find_command_by_text(self, text: str) -> Optional[Tuple[Type[BaseCommand], dict, CommandInfo]]:
|
def find_command_by_text(self, text: str) -> Optional[Tuple[Type['BaseCommand'], dict, 'CommandInfo']]:
|
||||||
# sourcery skip: use-named-expression, use-next
|
# sourcery skip: use-named-expression, use-next
|
||||||
"""根据文本查找匹配的命令
|
"""根据文本查找匹配的命令
|
||||||
|
|
||||||
@@ -597,15 +638,15 @@ class ComponentRegistry:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# === Tool 特定查询方法 ===
|
# === Tool 特定查询方法 ===
|
||||||
def get_tool_registry(self) -> Dict[str, Type[BaseTool]]:
|
def get_tool_registry(self) -> Dict[str, Type['BaseTool']]:
|
||||||
"""获取Tool注册表"""
|
"""获取Tool注册表"""
|
||||||
return self._tool_registry.copy()
|
return self._tool_registry.copy()
|
||||||
|
|
||||||
def get_llm_available_tools(self) -> Dict[str, Type[BaseTool]]:
|
def get_llm_available_tools(self) -> Dict[str, Type['BaseTool']]:
|
||||||
"""获取LLM可用的Tool列表"""
|
"""获取LLM可用的Tool列表"""
|
||||||
return self._llm_available_tools.copy()
|
return self._llm_available_tools.copy()
|
||||||
|
|
||||||
def get_registered_tool_info(self, tool_name: str) -> Optional[ToolInfo]:
|
def get_registered_tool_info(self, tool_name: str) -> Optional['ToolInfo']:
|
||||||
"""获取Tool信息
|
"""获取Tool信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -618,13 +659,13 @@ class ComponentRegistry:
|
|||||||
return info if isinstance(info, ToolInfo) else None
|
return info if isinstance(info, ToolInfo) else None
|
||||||
|
|
||||||
# === PlusCommand 特定查询方法 ===
|
# === PlusCommand 特定查询方法 ===
|
||||||
def get_plus_command_registry(self) -> Dict[str, Type[PlusCommand]]:
|
def get_plus_command_registry(self) -> Dict[str, Type['PlusCommand']]:
|
||||||
"""获取PlusCommand注册表"""
|
"""获取PlusCommand注册表"""
|
||||||
if not hasattr(self, "_plus_command_registry"):
|
if not hasattr(self, "_plus_command_registry"):
|
||||||
pass
|
pass
|
||||||
return self._plus_command_registry.copy()
|
return self._plus_command_registry.copy()
|
||||||
|
|
||||||
def get_registered_plus_command_info(self, command_name: str) -> Optional[PlusCommandInfo]:
|
def get_registered_plus_command_info(self, command_name: str) -> Optional['PlusCommandInfo']:
|
||||||
"""获取PlusCommand信息
|
"""获取PlusCommand信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -638,26 +679,44 @@ class ComponentRegistry:
|
|||||||
|
|
||||||
# === EventHandler 特定查询方法 ===
|
# === EventHandler 特定查询方法 ===
|
||||||
|
|
||||||
def get_event_handler_registry(self) -> Dict[str, Type[BaseEventHandler]]:
|
def get_event_handler_registry(self) -> Dict[str, Type['BaseEventHandler']]:
|
||||||
"""获取事件处理器注册表"""
|
"""获取事件处理器注册表"""
|
||||||
return self._event_handler_registry.copy()
|
return self._event_handler_registry.copy()
|
||||||
|
|
||||||
def get_registered_event_handler_info(self, handler_name: str) -> Optional[EventHandlerInfo]:
|
def get_registered_event_handler_info(self, handler_name: str) -> Optional['EventHandlerInfo']:
|
||||||
"""获取事件处理器信息"""
|
"""获取事件处理器信息"""
|
||||||
info = self.get_component_info(handler_name, ComponentType.EVENT_HANDLER)
|
info = self.get_component_info(handler_name, ComponentType.EVENT_HANDLER)
|
||||||
return info if isinstance(info, EventHandlerInfo) else None
|
return info if isinstance(info, EventHandlerInfo) else None
|
||||||
|
|
||||||
def get_enabled_event_handlers(self) -> Dict[str, Type[BaseEventHandler]]:
|
def get_enabled_event_handlers(self) -> Dict[str, Type['BaseEventHandler']]:
|
||||||
"""获取启用的事件处理器"""
|
"""获取启用的事件处理器"""
|
||||||
return self._enabled_event_handlers.copy()
|
return self._enabled_event_handlers.copy()
|
||||||
|
|
||||||
|
# === Chatter 特定查询方法 ===
|
||||||
|
def get_chatter_registry(self) -> Dict[str, Type['BaseChatter']]:
|
||||||
|
"""获取Chatter注册表"""
|
||||||
|
if not hasattr(self, '_chatter_registry'):
|
||||||
|
self._chatter_registry: Dict[str, Type[BaseChatter]] = {}
|
||||||
|
return self._chatter_registry.copy()
|
||||||
|
|
||||||
|
def get_enabled_chatter_registry(self) -> Dict[str, Type['BaseChatter']]:
|
||||||
|
"""获取启用的Chatter注册表"""
|
||||||
|
if not hasattr(self, '_enabled_chatter_registry'):
|
||||||
|
self._enabled_chatter_registry: Dict[str, Type[BaseChatter]] = {}
|
||||||
|
return self._enabled_chatter_registry.copy()
|
||||||
|
|
||||||
|
def get_registered_chatter_info(self, chatter_name: str) -> Optional['ChatterInfo']:
|
||||||
|
"""获取Chatter信息"""
|
||||||
|
info = self.get_component_info(chatter_name, ComponentType.CHATTER)
|
||||||
|
return info if isinstance(info, ChatterInfo) else None
|
||||||
|
|
||||||
# === 插件查询方法 ===
|
# === 插件查询方法 ===
|
||||||
|
|
||||||
def get_plugin_info(self, plugin_name: str) -> Optional[PluginInfo]:
|
def get_plugin_info(self, plugin_name: str) -> Optional['PluginInfo']:
|
||||||
"""获取插件信息"""
|
"""获取插件信息"""
|
||||||
return self._plugins.get(plugin_name)
|
return self._plugins.get(plugin_name)
|
||||||
|
|
||||||
def get_all_plugins(self) -> Dict[str, PluginInfo]:
|
def get_all_plugins(self) -> Dict[str, 'PluginInfo']:
|
||||||
"""获取所有插件"""
|
"""获取所有插件"""
|
||||||
return self._plugins.copy()
|
return self._plugins.copy()
|
||||||
|
|
||||||
@@ -665,7 +724,7 @@ class ComponentRegistry:
|
|||||||
# """获取所有启用的插件"""
|
# """获取所有启用的插件"""
|
||||||
# return {name: info for name, info in self._plugins.items() if info.enabled}
|
# return {name: info for name, info in self._plugins.items() if info.enabled}
|
||||||
|
|
||||||
def get_plugin_components(self, plugin_name: str) -> List[ComponentInfo]:
|
def get_plugin_components(self, plugin_name: str) -> List['ComponentInfo']:
|
||||||
"""获取插件的所有组件"""
|
"""获取插件的所有组件"""
|
||||||
plugin_info = self.get_plugin_info(plugin_name)
|
plugin_info = self.get_plugin_info(plugin_name)
|
||||||
return plugin_info.components if plugin_info else []
|
return plugin_info.components if plugin_info else []
|
||||||
@@ -709,6 +768,7 @@ class ComponentRegistry:
|
|||||||
tool_components: int = 0
|
tool_components: int = 0
|
||||||
events_handlers: int = 0
|
events_handlers: int = 0
|
||||||
plus_command_components: int = 0
|
plus_command_components: int = 0
|
||||||
|
chatter_components: int = 0
|
||||||
for component in self._components.values():
|
for component in self._components.values():
|
||||||
if component.component_type == ComponentType.ACTION:
|
if component.component_type == ComponentType.ACTION:
|
||||||
action_components += 1
|
action_components += 1
|
||||||
@@ -720,12 +780,15 @@ class ComponentRegistry:
|
|||||||
events_handlers += 1
|
events_handlers += 1
|
||||||
elif component.component_type == ComponentType.PLUS_COMMAND:
|
elif component.component_type == ComponentType.PLUS_COMMAND:
|
||||||
plus_command_components += 1
|
plus_command_components += 1
|
||||||
|
elif component.component_type == ComponentType.CHATTER:
|
||||||
|
chatter_components += 1
|
||||||
return {
|
return {
|
||||||
"action_components": action_components,
|
"action_components": action_components,
|
||||||
"command_components": command_components,
|
"command_components": command_components,
|
||||||
"tool_components": tool_components,
|
"tool_components": tool_components,
|
||||||
"event_handlers": events_handlers,
|
"event_handlers": events_handlers,
|
||||||
"plus_command_components": plus_command_components,
|
"plus_command_components": plus_command_components,
|
||||||
|
"chatter_components": chatter_components,
|
||||||
"total_components": len(self._components),
|
"total_components": len(self._components),
|
||||||
"total_plugins": len(self._plugins),
|
"total_plugins": len(self._plugins),
|
||||||
"components_by_type": {
|
"components_by_type": {
|
||||||
@@ -734,6 +797,10 @@ class ComponentRegistry:
|
|||||||
"enabled_components": len([c for c in self._components.values() if c.enabled]),
|
"enabled_components": len([c for c in self._components.values() if c.enabled]),
|
||||||
"enabled_plugins": len([p for p in self._plugins.values() if p.enabled]),
|
"enabled_plugins": len([p for p in self._plugins.values() if p.enabled]),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"enabled_components": len([c for c in self._components.values() if c.enabled]),
|
||||||
|
"enabled_plugins": len([p for p in self._plugins.values() if p.enabled]),
|
||||||
|
}
|
||||||
|
|
||||||
# === 组件移除相关 ===
|
# === 组件移除相关 ===
|
||||||
|
|
||||||
|
|||||||
@@ -378,13 +378,14 @@ class PluginManager:
|
|||||||
tool_count = stats.get("tool_components", 0)
|
tool_count = stats.get("tool_components", 0)
|
||||||
event_handler_count = stats.get("event_handlers", 0)
|
event_handler_count = stats.get("event_handlers", 0)
|
||||||
plus_command_count = stats.get("plus_command_components", 0)
|
plus_command_count = stats.get("plus_command_components", 0)
|
||||||
|
chatter_count = stats.get("chatter_components", 0)
|
||||||
total_components = stats.get("total_components", 0)
|
total_components = stats.get("total_components", 0)
|
||||||
|
|
||||||
# 📋 显示插件加载总览
|
# 📋 显示插件加载总览
|
||||||
if total_registered > 0:
|
if total_registered > 0:
|
||||||
logger.info("🎉 插件系统加载完成!")
|
logger.info("🎉 插件系统加载完成!")
|
||||||
logger.info(
|
logger.info(
|
||||||
f"📊 总览: {total_registered}个插件, {total_components}个组件 (Action: {action_count}, Command: {command_count}, Tool: {tool_count}, PlusCommand: {plus_command_count}, EventHandler: {event_handler_count})"
|
f"📊 总览: {total_registered}个插件, {total_components}个组件 (Action: {action_count}, Command: {command_count}, Tool: {tool_count}, PlusCommand: {plus_command_count}, EventHandler: {event_handler_count}, Chatter: {chatter_count})"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 显示详细的插件列表
|
# 显示详细的插件列表
|
||||||
@@ -440,6 +441,12 @@ class PluginManager:
|
|||||||
if plus_command_components:
|
if plus_command_components:
|
||||||
plus_command_names = [c.name for c in plus_command_components]
|
plus_command_names = [c.name for c in plus_command_components]
|
||||||
logger.info(f" ⚡ PlusCommand组件: {', '.join(plus_command_names)}")
|
logger.info(f" ⚡ PlusCommand组件: {', '.join(plus_command_names)}")
|
||||||
|
chatter_components = [
|
||||||
|
c for c in plugin_info.components if c.component_type == ComponentType.CHATTER
|
||||||
|
]
|
||||||
|
if chatter_components:
|
||||||
|
chatter_names = [c.name for c in chatter_components]
|
||||||
|
logger.info(f" 🗣️ Chatter组件: {', '.join(chatter_names)}")
|
||||||
if event_handler_components:
|
if event_handler_components:
|
||||||
event_handler_names = [c.name for c in event_handler_components]
|
event_handler_names = [c.name for c in event_handler_components]
|
||||||
logger.info(f" 📢 EventHandler组件: {', '.join(event_handler_names)}")
|
logger.info(f" 📢 EventHandler组件: {', '.join(event_handler_names)}")
|
||||||
|
|||||||
125
src/plugins/built_in/chatter/README.md
Normal file
125
src/plugins/built_in/chatter/README.md
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# 亲和力聊天处理器插件
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
这是一个内置的chatter插件,实现了基于亲和力流的智能聊天处理器,具有兴趣度评分和人物关系构建功能。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **智能兴趣度评分**: 自动识别和评估用户兴趣话题
|
||||||
|
- **人物关系系统**: 根据互动历史建立和维持用户关系
|
||||||
|
- **多聊天类型支持**: 支持私聊和群聊场景
|
||||||
|
- **插件化架构**: 完全集成到插件系统中
|
||||||
|
|
||||||
|
## 组件架构
|
||||||
|
|
||||||
|
### BaseChatter (抽象基类)
|
||||||
|
- 位置: `src/plugin_system/base/base_chatter.py`
|
||||||
|
- 功能: 定义所有chatter组件的基础接口
|
||||||
|
- 必须实现的方法: `execute(context: StreamContext) -> dict`
|
||||||
|
|
||||||
|
### ChatterManager (管理器)
|
||||||
|
- 位置: `src/chat/chatter_manager.py`
|
||||||
|
- 功能: 管理和调度所有chatter组件
|
||||||
|
- 特性: 自动从插件系统注册和发现chatter组件
|
||||||
|
|
||||||
|
### AffinityChatter (具体实现)
|
||||||
|
- 位置: `src/plugins/built_in/chatter/affinity_chatter.py`
|
||||||
|
- 功能: 亲和力流聊天处理器的具体实现
|
||||||
|
- 支持的聊天类型: PRIVATE, GROUP
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 基本使用
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.chat.chatter_manager import ChatterManager
|
||||||
|
from src.chat.planner_actions.action_manager import ActionManager
|
||||||
|
|
||||||
|
# 初始化
|
||||||
|
action_manager = ActionManager()
|
||||||
|
chatter_manager = ChatterManager(action_manager)
|
||||||
|
|
||||||
|
# 处理消息流
|
||||||
|
result = await chatter_manager.process_stream_context(stream_id, context)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 创建自定义Chatter
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.plugin_system.base.base_chatter import BaseChatter
|
||||||
|
from src.plugin_system.base.component_types import ChatType, ComponentType
|
||||||
|
from src.plugin_system.base.component_types import ChatterInfo
|
||||||
|
|
||||||
|
class CustomChatter(BaseChatter):
|
||||||
|
chat_types = [ChatType.PRIVATE] # 只支持私聊
|
||||||
|
|
||||||
|
async def execute(self, context: StreamContext) -> dict:
|
||||||
|
# 实现你的聊天逻辑
|
||||||
|
return {"success": True, "message": "处理完成"}
|
||||||
|
|
||||||
|
# 在插件中注册
|
||||||
|
async def on_load(self):
|
||||||
|
chatter_info = ChatterInfo(
|
||||||
|
name="custom_chatter",
|
||||||
|
component_type=ComponentType.CHATTER,
|
||||||
|
description="自定义聊天处理器",
|
||||||
|
enabled=True,
|
||||||
|
plugin_name=self.name,
|
||||||
|
chat_type_allow=ChatType.PRIVATE
|
||||||
|
)
|
||||||
|
|
||||||
|
ComponentRegistry.register_component(
|
||||||
|
component_info=chatter_info,
|
||||||
|
component_class=CustomChatter
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置
|
||||||
|
|
||||||
|
### 插件配置文件
|
||||||
|
- 位置: `src/plugins/built_in/chatter/_manifest.json`
|
||||||
|
- 包含插件信息和组件配置
|
||||||
|
|
||||||
|
### 聊天类型
|
||||||
|
- `PRIVATE`: 私聊
|
||||||
|
- `GROUP`: 群聊
|
||||||
|
- `ALL`: 所有类型
|
||||||
|
|
||||||
|
## 核心概念
|
||||||
|
|
||||||
|
### 1. 兴趣值系统
|
||||||
|
- 自动识别同类话题
|
||||||
|
- 兴趣值会根据聊天频率增减
|
||||||
|
- 支持新话题的自动学习
|
||||||
|
|
||||||
|
### 2. 人物关系系统
|
||||||
|
- 根据互动质量建立关系分
|
||||||
|
- 不同关系分对应不同的回复风格
|
||||||
|
- 支持情感化的交流
|
||||||
|
|
||||||
|
### 3. 执行流程
|
||||||
|
1. 接收StreamContext
|
||||||
|
2. 使用ActionPlanner进行规划
|
||||||
|
3. 执行相应的Action
|
||||||
|
4. 返回处理结果
|
||||||
|
|
||||||
|
## 扩展开发
|
||||||
|
|
||||||
|
### 添加新的Chatter类型
|
||||||
|
1. 继承BaseChatter类
|
||||||
|
2. 实现execute方法
|
||||||
|
3. 在插件中注册组件
|
||||||
|
4. 配置支持的聊天类型
|
||||||
|
|
||||||
|
### 集成现有功能
|
||||||
|
- 使用ActionPlanner进行动作规划
|
||||||
|
- 通过ActionManager执行动作
|
||||||
|
- 利用现有的记忆和知识系统
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 所有chatter组件必须实现`execute`方法
|
||||||
|
2. 插件注册时需要指定支持的聊天类型
|
||||||
|
3. 组件名称不能包含点号(.)
|
||||||
|
4. 确保在插件卸载时正确清理资源
|
||||||
8
src/plugins/built_in/chatter/__init__.py
Normal file
8
src/plugins/built_in/chatter/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"""
|
||||||
|
亲和力聊天处理器插件
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .plugin import AffinityChatterPlugin
|
||||||
|
from .affinity_chatter import AffinityChatter
|
||||||
|
|
||||||
|
__all__ = ["AffinityChatterPlugin", "AffinityChatter"]
|
||||||
23
src/plugins/built_in/chatter/_manifest.json
Normal file
23
src/plugins/built_in/chatter/_manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 1,
|
||||||
|
"name": "affinity_chatter",
|
||||||
|
"display_name": "Affinity Flow Chatter",
|
||||||
|
"description": "Built-in chatter plugin for affinity flow with interest scoring and relationship building",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "MoFox",
|
||||||
|
"plugin_class": "AffinityChatterPlugin",
|
||||||
|
"enabled": true,
|
||||||
|
"is_built_in": true,
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"name": "affinity_chatter",
|
||||||
|
"type": "chatter",
|
||||||
|
"description": "Affinity flow chatter with intelligent interest scoring and relationship building",
|
||||||
|
"enabled": true,
|
||||||
|
"chat_type_allow": ["all"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"host_application": { "min_version": "0.8.0" },
|
||||||
|
"keywords": ["chatter", "affinity", "conversation"],
|
||||||
|
"categories": ["Chat", "AI"]
|
||||||
|
}
|
||||||
206
src/plugins/built_in/chatter/affinity_chatter.py
Normal file
206
src/plugins/built_in/chatter/affinity_chatter.py
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
"""
|
||||||
|
亲和力聊天处理器
|
||||||
|
基于现有的AffinityFlowChatter重构为插件化组件
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
from datetime import datetime
|
||||||
|
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.common.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger("affinity_chatter")
|
||||||
|
|
||||||
|
|
||||||
|
class AffinityChatter(BaseChatter):
|
||||||
|
"""亲和力聊天处理器"""
|
||||||
|
chatter_name: str = "AffinityChatter"
|
||||||
|
chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型"
|
||||||
|
chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型
|
||||||
|
|
||||||
|
def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager):
|
||||||
|
"""
|
||||||
|
初始化亲和力聊天处理器
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stream_id: 聊天流ID
|
||||||
|
planner: 动作规划器
|
||||||
|
action_manager: 动作管理器
|
||||||
|
"""
|
||||||
|
super().__init__(stream_id, planner, 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"AffinityChatter(stream_id={self.stream_id}, messages={self.stats['messages_processed']})"
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""详细字符串表示"""
|
||||||
|
return (
|
||||||
|
f"AffinityChatter(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)})"
|
||||||
|
)
|
||||||
46
src/plugins/built_in/chatter/plugin.py
Normal file
46
src/plugins/built_in/chatter/plugin.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
亲和力聊天处理器插件
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import List, Tuple, Type
|
||||||
|
|
||||||
|
from src.plugin_system.apis.plugin_register_api import register_plugin
|
||||||
|
from src.plugin_system.base.base_plugin import BasePlugin
|
||||||
|
from src.plugin_system.base.component_types import ComponentInfo, ChatterInfo, ComponentType, ChatType
|
||||||
|
from src.common.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger("affinity_chatter_plugin")
|
||||||
|
|
||||||
|
|
||||||
|
@register_plugin
|
||||||
|
class AffinityChatterPlugin(BasePlugin):
|
||||||
|
"""亲和力聊天处理器插件
|
||||||
|
|
||||||
|
- 延迟导入 `AffinityChatter` 并通过组件注册器注册为聊天处理器
|
||||||
|
- 提供 `get_plugin_components` 以兼容插件注册机制
|
||||||
|
"""
|
||||||
|
|
||||||
|
plugin_name: str = "affinity_chatter"
|
||||||
|
enable_plugin: bool = True
|
||||||
|
dependencies: list[str] = []
|
||||||
|
python_dependencies: list[str] = []
|
||||||
|
config_file_name: str = ""
|
||||||
|
|
||||||
|
# 简单的 config_schema 占位(如果将来需要配置可扩展)
|
||||||
|
config_schema = {}
|
||||||
|
|
||||||
|
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||||
|
"""返回插件包含的组件列表(ChatterInfo, AffinityChatter)
|
||||||
|
|
||||||
|
这里采用延迟导入 AffinityChatter 来避免循环依赖和启动顺序问题。
|
||||||
|
如果导入失败则返回空列表以让注册过程继续而不崩溃。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 延迟导入以避免循环导入
|
||||||
|
from .affinity_chatter import AffinityChatter
|
||||||
|
|
||||||
|
return [(AffinityChatter.get_chatter_info(), AffinityChatter)]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载 AffinityChatter 时出错: {e}")
|
||||||
|
return []
|
||||||
Reference in New Issue
Block a user