Add files via upload

pull/1058/head
A0000Xz 2025-06-24 00:58:23 +08:00 committed by GitHub
parent ed1724b29c
commit d1de43b09a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 231 additions and 230 deletions

View File

@ -1,230 +1,231 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Dict, Tuple, Optional, List from typing import Dict, Tuple, Optional, List
from src.common.logger import get_logger from src.common.logger import get_logger
from src.plugin_system.base.component_types import CommandInfo, ComponentType from src.plugin_system.base.component_types import CommandInfo, ComponentType
from src.chat.message_receive.message import MessageRecv from src.chat.message_receive.message import MessageRecv
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
logger = get_logger("base_command") logger = get_logger("base_command")
class BaseCommand(ABC): class BaseCommand(ABC):
"""Command组件基类 """Command组件基类
Command是插件的一种组件类型用于处理命令请求 Command是插件的一种组件类型用于处理命令请求
子类可以通过类属性定义命令模式 子类可以通过类属性定义命令模式
- command_pattern: 命令匹配的正则表达式 - command_pattern: 命令匹配的正则表达式
- command_help: 命令帮助信息 - command_help: 命令帮助信息
- command_examples: 命令使用示例列表 - command_examples: 命令使用示例列表
- intercept_message: 是否拦截消息处理默认True拦截False继续传递 - intercept_message: 是否拦截消息处理默认True拦截False继续传递
""" """
command_name: str = "" command_name: str = ""
command_description: str = "" command_description: str = ""
# 默认命令设置(子类可以覆盖) # 默认命令设置(子类可以覆盖)
command_pattern: str = "" command_pattern: str = ""
command_help: str = "" command_help: str = ""
command_examples: List[str] = [] command_examples: List[str] = []
intercept_message: bool = True # 默认拦截消息,不继续处理 intercept_message: bool = True # 默认拦截消息,不继续处理
def __init__(self, message: MessageRecv, plugin_config: dict = None): def __init__(self, message: MessageRecv, plugin_config: dict = None):
"""初始化Command组件 """初始化Command组件
Args: Args:
message: 接收到的消息对象 message: 接收到的消息对象
plugin_config: 插件配置字典 plugin_config: 插件配置字典
""" """
self.message = message self.message = message
self.matched_groups: Dict[str, str] = {} # 存储正则表达式匹配的命名组 self.matched_groups: Dict[str, str] = {} # 存储正则表达式匹配的命名组
self.plugin_config = plugin_config or {} # 直接存储插件配置字典 self.plugin_config = plugin_config or {} # 直接存储插件配置字典
self.log_prefix = "[Command]" self.log_prefix = "[Command]"
logger.debug(f"{self.log_prefix} Command组件初始化完成") logger.debug(f"{self.log_prefix} Command组件初始化完成")
def set_matched_groups(self, groups: Dict[str, str]) -> None: def set_matched_groups(self, groups: Dict[str, str]) -> None:
"""设置正则表达式匹配的命名组 """设置正则表达式匹配的命名组
Args: Args:
groups: 正则表达式匹配的命名组 groups: 正则表达式匹配的命名组
""" """
self.matched_groups = groups self.matched_groups = groups
@abstractmethod @abstractmethod
async def execute(self) -> Tuple[bool, Optional[str]]: async def execute(self) -> Tuple[bool, Optional[str]]:
"""执行Command的抽象方法子类必须实现 """执行Command的抽象方法子类必须实现
Returns: Returns:
Tuple[bool, Optional[str]]: (是否执行成功, 可选的回复消息) Tuple[bool, Optional[str]]: (是否执行成功, 可选的回复消息)
""" """
pass pass
def get_config(self, key: str, default=None): def get_config(self, key: str, default=None):
"""获取插件配置值,支持嵌套键访问 """获取插件配置值,支持嵌套键访问
Args: Args:
key: 配置键名支持嵌套访问如 "section.subsection.key" key: 配置键名支持嵌套访问如 "section.subsection.key"
default: 默认值 default: 默认值
Returns: Returns:
Any: 配置值或默认值 Any: 配置值或默认值
""" """
if not self.plugin_config: if not self.plugin_config:
return default return default
# 支持嵌套键访问 # 支持嵌套键访问
keys = key.split(".") keys = key.split(".")
current = self.plugin_config current = self.plugin_config
for k in keys: for k in keys:
if isinstance(current, dict) and k in current: if isinstance(current, dict) and k in current:
current = current[k] current = current[k]
else: else:
return default return default
return current return current
async def send_text(self, content: str, reply_to: str = "") -> bool: async def send_text(self, content: str, reply_to: str = "") -> bool:
"""发送回复消息 """发送回复消息
Args: Args:
content: 回复内容 content: 回复内容
reply_to: 回复消息格式为"发送者:消息内容" reply_to: 回复消息格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
# 获取聊天流信息 # 获取聊天流信息
chat_stream = self.message.chat_stream chat_stream = self.message.chat_stream
if not chat_stream or not hasattr(chat_stream, "stream_id"): if not chat_stream or not hasattr(chat_stream, "stream_id"):
logger.error(f"{self.log_prefix} 缺少聊天流或stream_id") logger.error(f"{self.log_prefix} 缺少聊天流或stream_id")
return False return False
return await send_api.text_to_stream(text=content, stream_id=chat_stream.stream_id, reply_to=reply_to) return await send_api.text_to_stream(text=content, stream_id=chat_stream.stream_id, reply_to=reply_to)
async def send_type( async def send_type(
self, message_type: str, content: str, display_message: str = "", typing: bool = False, reply_to: str = "" self, message_type: str, content: str, display_message: str = "", typing: bool = False, reply_to: str = ""
) -> bool: ) -> bool:
"""发送指定类型的回复消息到当前聊天环境 """发送指定类型的回复消息到当前聊天环境
Args: Args:
message_type: 消息类型"text""image""emoji" message_type: 消息类型"text""image""emoji"
content: 消息内容 content: 消息内容
display_message: 显示消息可选 display_message: 显示消息可选
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息格式为"发送者:消息内容" reply_to: 回复消息格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
# 获取聊天流信息 # 获取聊天流信息
chat_stream = self.message.chat_stream chat_stream = self.message.chat_stream
if not chat_stream or not hasattr(chat_stream, "stream_id"): if not chat_stream or not hasattr(chat_stream, "stream_id"):
logger.error(f"{self.log_prefix} 缺少聊天流或stream_id") logger.error(f"{self.log_prefix} 缺少聊天流或stream_id")
return False return False
return await send_api.custom_to_stream( return await send_api.custom_to_stream(
message_type=message_type, message_type=message_type,
content=content, content=content,
stream_id=chat_stream.stream_id, stream_id=chat_stream.stream_id,
display_message=display_message, display_message=display_message,
typing=typing, typing=typing,
reply_to=reply_to, reply_to=reply_to,
) )
async def send_command( async def send_command(
self, command_name: str, args: dict = None, display_message: str = "", storage_message: bool = True self, command_name: str, args: dict = None, display_message: str = "", storage_message: bool = True
) -> bool: ) -> bool:
"""发送命令消息 """发送命令消息
Args: Args:
command_name: 命令名称 command_name: 命令名称
args: 命令参数 args: 命令参数
display_message: 显示消息 display_message: 显示消息
storage_message: 是否存储消息到数据库 storage_message: 是否存储消息到数据库
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
try: try:
# 获取聊天流信息 # 获取聊天流信息
chat_stream = self.message.chat_stream chat_stream = self.message.chat_stream
if not chat_stream or not hasattr(chat_stream, "stream_id"): if not chat_stream or not hasattr(chat_stream, "stream_id"):
logger.error(f"{self.log_prefix} 缺少聊天流或stream_id") logger.error(f"{self.log_prefix} 缺少聊天流或stream_id")
return False return False
# 构造命令数据 # 构造命令数据
command_data = {"name": command_name, "args": args or {}} command_data = {"name": command_name, "args": args or {}}
success = await send_api.command_to_stream( success = await send_api.command_to_stream(
command=command_data, command=command_data,
stream_id=chat_stream.stream_id, stream_id=chat_stream.stream_id,
storage_message=storage_message, storage_message=storage_message,
) display_message=display_message
)
if success:
logger.info(f"{self.log_prefix} 成功发送命令: {command_name}") if success:
else: logger.info(f"{self.log_prefix} 成功发送命令: {command_name}")
logger.error(f"{self.log_prefix} 发送命令失败: {command_name}") else:
logger.error(f"{self.log_prefix} 发送命令失败: {command_name}")
return success
return success
except Exception as e:
logger.error(f"{self.log_prefix} 发送命令时出错: {e}") except Exception as e:
return False logger.error(f"{self.log_prefix} 发送命令时出错: {e}")
return False
async def send_emoji(self, emoji_base64: str) -> bool:
"""发送表情包 async def send_emoji(self, emoji_base64: str) -> bool:
"""发送表情包
Args:
emoji_base64: 表情包的base64编码 Args:
emoji_base64: 表情包的base64编码
Returns:
bool: 是否发送成功 Returns:
""" bool: 是否发送成功
chat_stream = self.message.chat_stream """
if not chat_stream or not hasattr(chat_stream, "stream_id"): chat_stream = self.message.chat_stream
logger.error(f"{self.log_prefix} 缺少聊天流或stream_id") if not chat_stream or not hasattr(chat_stream, "stream_id"):
return False logger.error(f"{self.log_prefix} 缺少聊天流或stream_id")
return False
return await send_api.emoji_to_stream(emoji_base64, chat_stream.stream_id)
return await send_api.emoji_to_stream(emoji_base64, chat_stream.stream_id)
async def send_image(self, image_base64: str) -> bool:
"""发送图片 async def send_image(self, image_base64: str) -> bool:
"""发送图片
Args:
image_base64: 图片的base64编码 Args:
image_base64: 图片的base64编码
Returns:
bool: 是否发送成功 Returns:
""" bool: 是否发送成功
chat_stream = self.message.chat_stream """
if not chat_stream or not hasattr(chat_stream, "stream_id"): chat_stream = self.message.chat_stream
logger.error(f"{self.log_prefix} 缺少聊天流或stream_id") if not chat_stream or not hasattr(chat_stream, "stream_id"):
return False logger.error(f"{self.log_prefix} 缺少聊天流或stream_id")
return False
return await send_api.image_to_stream(image_base64, chat_stream.stream_id)
return await send_api.image_to_stream(image_base64, chat_stream.stream_id)
@classmethod
def get_command_info(cls) -> "CommandInfo": @classmethod
"""从类属性生成CommandInfo def get_command_info(cls) -> "CommandInfo":
"""从类属性生成CommandInfo
Args:
name: Command名称如果不提供则使用类名 Args:
description: Command描述如果不提供则使用类文档字符串 name: Command名称如果不提供则使用类名
description: Command描述如果不提供则使用类文档字符串
Returns:
CommandInfo: 生成的Command信息对象 Returns:
""" CommandInfo: 生成的Command信息对象
"""
return CommandInfo(
name=cls.command_name, return CommandInfo(
component_type=ComponentType.COMMAND, name=cls.command_name,
description=cls.command_description, component_type=ComponentType.COMMAND,
command_pattern=cls.command_pattern, description=cls.command_description,
command_help=cls.command_help, command_pattern=cls.command_pattern,
command_examples=cls.command_examples.copy() if cls.command_examples else [], command_help=cls.command_help,
intercept_message=cls.intercept_message, command_examples=cls.command_examples.copy() if cls.command_examples else [],
) intercept_message=cls.intercept_message,
)