欢迎使用QQ机器人插件系统!本文档将指导您开发功能强大的机器人插件。
现在插件可以在一次回复中发送多条不同类型的消息!
# 🆕 新功能:一次发送多条消息
return {
'response': [
MessageBuilder.text('📊 查询结果'),
MessageBuilder.text_card('详细数据...'),
MessageBuilder.markdown('## 分析报告\n...'),
MessageBuilder.text('✅ 查询完成')
],
'handled': True
}
主要优势: - ✅ 丰富表达 - 组合不同消息类型,提供更好的用户体验 - ✅ 逻辑清晰 - 将复杂回复分解为多个有序的消息部分 - ✅ 完全兼容 - 现有插件无需修改,新旧语法并存 - ✅ 灵活组合 - 支持文本、卡片、图片、Markdown等任意组合
我们的插件系统采用Hook驱动 + 命令发现的混合架构:
Plugins/
├── your_plugin/ # 插件目录
│ ├── __init__.py # 插件主文件(必需)
│ ├── config.py # 配置文件(可选)
│ ├── utils.py # 工具函数(可选)
│ └── README.md # 插件说明(推荐)
├── echo/ # 示例插件
└── help/ # 帮助插件
mkdir Plugins/my_plugin
cd Plugins/my_plugin
创建 __init__.py 文件:
"""
我的第一个插件
"""
from Core.plugin.base import BasePlugin
from Core.logging.file_logger import log_info
from Core.message.message_builder import MessageBuilder
class Plugin(BasePlugin):
"""我的插件类"""
def __init__(self):
super().__init__()
# 插件信息
self.name = "MyPlugin"
self.version = "1.0.0"
self.description = "我的第一个QQ机器人插件"
self.author = "Your Name"
# 注册命令信息(用于展示和帮助)
self.register_command_info('hello', '打招呼', '/hello')
self.register_command_info('info', '显示插件信息', '/info')
# 注册Hook事件处理器
self.hooks = {
'message_received': [self.handle_message_hook],
'before_bot_start': [self.on_before_bot_start_hook],
'after_bot_start': [self.on_after_bot_start_hook],
'before_bot_stop': [self.on_before_bot_stop_hook],
'after_bot_stop': [self.on_after_bot_stop_hook]
}
log_info(0, f"{self.name}插件初始化完成", "PLUGIN_INIT", plugin=self.name)
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook"""
try:
content = message_data.get('content', '').strip()
# 处理命令
if content.startswith('/'):
return self._handle_command(content, bot_id)
# 处理自然语言
if content.lower() in ['hello', '你好']:
return {
'response': MessageBuilder.text(f'你好!我是{self.name}插件 👋'),
'handled': True
}
# 不处理其他消息
return {'handled': False}
except Exception as e:
log_info(bot_id or 0, f"{self.name}插件处理消息异常: {e}", "PLUGIN_ERROR")
return {'handled': False}
def _handle_command(self, content, bot_id=None):
"""处理命令"""
# 解析命令
parts = content[1:].split()
if not parts:
return {'handled': False}
command = parts[0].lower()
args = parts[1:] if len(parts) > 1 else []
# 处理支持的命令
if command == 'hello':
return {
'response': MessageBuilder.text(f'你好!我是{self.name}插件 👋'),
'handled': True
}
elif command == 'info':
# 🆕 多消息回复示例
return {
'response': [
MessageBuilder.text(f'📋 {self.name} 插件信息'),
MessageBuilder.text_card(
text=f'插件名称:{self.name}\n版本:{self.version}\n作者:{self.author}',
description=self.description,
prompt='插件详细信息'
),
MessageBuilder.text('✨ 感谢使用!')
],
'handled': True
}
return {'handled': False}
def on_before_bot_start_hook(self, bot_id, bot_config):
"""机器人启动前Hook"""
return {'message': f'{self.name}插件准备为机器人 {bot_id} 初始化'}
def on_after_bot_start_hook(self, bot_id, bot_config):
"""机器人启动后Hook"""
return {'message': f'{self.name}插件已为机器人 {bot_id} 准备就绪'}
def on_before_bot_stop_hook(self, bot_id):
"""机器人停止前Hook"""
return {'message': f'{self.name}插件准备为机器人 {bot_id} 清理资源'}
def on_after_bot_stop_hook(self, bot_id):
"""机器人停止后Hook"""
return {'message': f'{self.name}插件已为机器人 {bot_id} 清理完成'}
重启机器人服务,插件将自动加载。
系统会自动扫描 Plugins/ 目录下的所有子目录:
__ 开头(如 __pycache__)__init__.py 文件__init__.py 中必须有 Plugin 类系统会自动加载以下默认插件:
echo - 回声插件help - 帮助插件# 1. 插件发现
plugins = plugin_manager.discover_plugins()
# 2. 插件加载
for plugin_name in plugins:
plugin_manager.load_plugin(plugin_name)
# 3. Hook注册
# 系统自动注册插件的hooks到Hook系统
# 4. 插件卸载(可选)
plugin_manager.unload_plugin(plugin_name)
# 5. 插件重载(可选)
plugin_manager.reload_plugin(plugin_name)
# 获取插件信息
plugin_info = plugin_manager.get_plugin_info('my_plugin')
# 获取所有插件
all_plugins = plugin_manager.get_all_plugins()
# 检查插件是否加载
is_loaded = 'my_plugin' in plugin_manager.plugins
| Hook事件 | 触发时机 | 参数 | 返回值 |
|---|---|---|---|
message_received |
收到消息时 | message_data, bot_id |
{'response': MessageBuilder对象或数组, 'handled': bool} |
before_bot_start |
机器人启动前 | bot_id, bot_config |
{'message': str} (可选) |
after_bot_start |
机器人启动后 | bot_id, bot_config |
{'message': str} (可选) |
before_bot_stop |
机器人停止前 | bot_id |
{'message': str} (可选) |
after_bot_stop |
机器人停止后 | bot_id |
{'message': str} (可选) |
message_data = {
'content': '消息内容', # 消息文本
'type': 'c2c', # 消息类型: c2c(私聊), channel(频道), group_at(群聊@)
'id': 'message_id', # 消息ID
'msg_id': 'message_id', # 消息ID(用于回复)
'timestamp': '2025-01-01...', # 时间戳
'author': { # 发送者信息
'user_openid': 'user_123',
'id': 'author_id',
'username': 'user_name' # 用户名(如果有)
},
# QQ频道消息额外字段
'channel_id': 'channel_123', # 频道ID(仅频道消息)
'guild_id': 'guild_456', # 服务器ID(仅频道消息)
# 群聊消息额外字段
'group_openid': 'group_123', # 群聊ID(仅群聊消息)
# 原始事件数据(用于高级处理)
'raw_event': {...} # 完整的QQ事件数据
}
c2c - 单聊消息(私聊)channel - 频道消息group_at - 群聊@消息direct_message - 私信消息at_message - 公域频道@消息def handle_message_hook(self, message_data, bot_id=None):
"""安全地获取消息信息"""
# 安全获取消息内容
content = message_data.get('content', '').strip()
# 安全获取消息类型
msg_type = message_data.get('type', 'unknown')
# 安全获取发送者信息
author = message_data.get('author', {})
user_id = author.get('user_openid') or author.get('id', 'unknown')
username = author.get('username', '未知用户')
# 根据消息类型获取特定信息
if msg_type == 'group_at':
group_id = message_data.get('group_openid')
elif msg_type == 'channel':
channel_id = message_data.get('channel_id')
guild_id = message_data.get('guild_id')
# 处理消息...
return {'handled': False}
# 🆕 单条消息回复
return {
'response': MessageBuilder.text('单条回复内容'),
'handled': True
}
# 🆕 多条消息回复(新功能!)
return {
'response': [
MessageBuilder.text('第一条消息'),
MessageBuilder.markdown('## 第二条消息\n这是Markdown格式'),
MessageBuilder.image('https://example.com/image.jpg', '第三条图片消息')
],
'handled': True
}
# 🆕 混合类型多消息回复
return {
'response': [
MessageBuilder.text('📊 数据查询结果:'),
MessageBuilder.text_card(
text='详细数据内容...',
description='数据卡片',
prompt='点击查看详情'
),
MessageBuilder.text('✅ 查询完成!')
],
'handled': True
}
# 没有处理消息,让其他插件处理
return {'handled': False}
# 处理了消息,但不回复
return {'handled': True}
# 返回状态消息
return {'message': '操作完成'}
# 或者返回空
return {}
Hook系统内置了频率限制机制,防止插件滥用:
# 插件开发者无需特殊处理,系统自动管理频率限制
def handle_message_hook(self, message_data, bot_id=None):
# 正常编写处理逻辑即可
return {'response': '处理结果', 'handled': True}
Hook系统具有完善的错误处理机制:
def handle_message_hook(self, message_data, bot_id=None):
try:
# 您的处理逻辑
return self.process_message(message_data)
except Exception as e:
# 异常会被Hook系统自动捕获和记录
# 建议在插件内部也进行适当的错误处理
return {'handled': False}
可以通过自定义Hook事件实现插件间通信:
# 插件A:触发自定义事件
class PluginA(BasePlugin):
def some_method(self):
# 通过插件管理器触发自定义Hook
from Core.bot.manager import get_bot_manager
bot_manager = get_bot_manager()
bot_manager.plugin_manager.trigger_hook('custom_data_update', {'data': 'some_value'})
# 插件B:监听自定义事件
class PluginB(BasePlugin):
def __init__(self):
super().__init__()
self.hooks = {
'custom_data_update': [self.handle_data_update]
}
def handle_data_update(self, data):
# 处理来自其他插件的数据
print(f"收到数据更新: {data}")
MessageBuilder是QQ机器人系统的核心消息构建工具,提供了统一的消息格式化接口。它支持多种消息类型,确保插件能够发送各种格式的消息。
from Core.message.message_builder import MessageBuilder
最基础的消息类型,用于发送纯文本内容:
# 基础文本消息
def handle_message_hook(self, message_data, bot_id=None):
if message_data.get('content') == '/hello':
return {
'response': MessageBuilder.text('你好!欢迎使用QQ机器人!'),
'handled': True
}
支持Markdown格式的富文本消息:
def handle_help_command(self):
markdown_content = """
# 🤖 机器人帮助
## 📋 可用命令
### 基础命令
- `/help` - 显示此帮助信息
- `/status` - 查看机器人状态
- `/ping` - 测试连接
### 功能命令
- `/weather [城市]` - 查询天气
- `/joke` - 随机笑话
- `/time` - 当前时间
## 💡 使用提示
发送命令时请确保格式正确,如有问题请联系管理员。
"""
return {
'response': MessageBuilder.markdown(markdown_content),
'handled': True
}
QQ官方支持多种富媒体消息类型,包括图片、视频、语音和文件。
支持格式:png/jpg
def handle_image_command(self, args):
if not args:
return {
'response': MessageBuilder.text('请提供图片URL'),
'handled': True
}
image_url = args[0]
caption = "这是一张图片"
return {
'response': MessageBuilder.image(image_url, caption),
'handled': True
}
# 发送本地图片
def send_local_image(self):
local_path = "/path/to/image.jpg"
return {
'response': MessageBuilder.image(local_path, "本地图片"),
'handled': True
}
# 自动上传网络图片
def send_network_image(self):
return {
'response': MessageBuilder.image(
"https://example.com/image.jpg",
"网络图片",
auto_upload=True # 自动上传到QQ服务器
),
'handled': True
}
支持格式:mp4
def handle_video_command(self, args):
if not args:
return {
'response': MessageBuilder.text('请提供视频URL'),
'handled': True
}
video_url = args[0]
caption = "这是一个视频"
return {
'response': MessageBuilder.video(video_url, caption),
'handled': True
}
# 发送本地视频
def send_local_video(self):
return {
'response': MessageBuilder.video(
"/path/to/video.mp4",
"本地视频文件",
auto_upload=True
),
'handled': True
}
支持格式:silk
def handle_voice_command(self, args):
if not args:
return {
'response': MessageBuilder.text('请提供语音URL'),
'handled': True
}
voice_url = args[0]
caption = "这是一段语音"
return {
'response': MessageBuilder.voice(voice_url, caption),
'handled': True
}
# 发送本地语音
def send_local_voice(self):
return {
'response': MessageBuilder.voice(
"/path/to/voice.silk",
"本地语音文件",
auto_upload=True
),
'handled': True
}
支持各种文件格式(注意:根据QQ官方文档,文件类型暂不开放)
def handle_file_command(self, args):
if not args:
return {
'response': MessageBuilder.text('请提供文件URL'),
'handled': True
}
file_url = args[0]
caption = "这是一个文件"
return {
'response': MessageBuilder.file(file_url, caption),
'handled': True
}
# 注意:文件消息目前暂不开放使用
Embed消息提供丰富的结构化内容展示,支持标题、描述、字段和缩略图:
def handle_embed_command(self, args):
# 基础Embed消息
return {
'response': MessageBuilder.embed(
title="📊 数据报告",
description="这是一个详细的数据分析报告",
color=0x00ff00 # 绿色边框
),
'handled': True
}
# 带字段的Embed消息
def handle_detailed_embed(self):
fields = [
{'name': '用户数量', 'value': '1,234'},
{'name': '活跃度', 'value': '98.5%'},
{'name': '增长率', 'value': '+15.2%'}
]
return {
'response': MessageBuilder.embed(
title="🎯 系统状态",
description="当前系统运行状态良好",
fields=fields,
color=0x0099ff, # 蓝色边框
thumbnail="https://example.com/icon.png"
),
'handled': True
}
# 多彩Embed消息
def handle_colorful_embed(self):
return {
'response': MessageBuilder.embed(
title="⚠️ 警告信息",
description="检测到异常活动,请注意检查",
color=0xff6600, # 橙色边框
thumbnail="https://example.com/warning.png"
),
'handled': True
}
QQ官方提供的模板化消息,支持多种卡片样式:
用于展示文本内容的卡片形式:
def handle_text_card(self):
return {
'response': MessageBuilder.text_card(
text="这是文卡的主要内容,可以包含多行文本和详细信息。",
description="文卡描述",
prompt="提示文字"
),
'handled': True
}
# 带链接的文卡消息
def handle_text_card_with_link(self):
return {
'response': MessageBuilder.text_card_link(
text="点击下方链接访问官网",
button_text="🔗 访问官网",
button_url="https://example.com",
description="带链接的文卡",
prompt="点击链接跳转"
),
'handled': True
}
用于分享链接和网页内容:
def handle_link_card(self):
return {
'response': MessageBuilder.link_card(
title="网页标题",
description="网页描述内容",
url="https://example.com",
cover_image="https://example.com/cover.jpg"
),
'handled': True
}
用于展示简单信息的小型卡片:
def handle_small_card(self):
return {
'response': MessageBuilder.small_card(
title="通知标题",
subtitle="通知详细内容",
preview_image="https://example.com/preview.jpg",
icon_image="https://example.com/icon.png",
url="https://example.com"
),
'handled': True
}
用于展示大尺寸图片内容:
def handle_large_image(self):
return {
'response': MessageBuilder.large_image(
title="图片标题",
subtitle="图片描述",
image_url="https://example.com/large-image.jpg"
),
'handled': True
}
支持交互按钮的消息:
def handle_button_message(self):
buttons = [
{'text': '选项1', 'data': 'option_1'},
{'text': '选项2', 'data': 'option_2'},
{'text': '帮助', 'data': 'help'}
]
return {
'response': MessageBuilder.button_card(
title="请选择操作",
content="点击下方按钮进行操作",
buttons=buttons
),
'handled': True
}
构建文本消息:
# 简单文本
message = MessageBuilder.text("Hello World!")
# 多行文本
message = MessageBuilder.text("""
第一行
第二行
第三行
""")
# 带emoji的文本
message = MessageBuilder.text("🎉 恭喜你!操作成功完成!")
构建Markdown消息:
# 基础Markdown
message = MessageBuilder.markdown("**粗体文本** 和 *斜体文本*")
# 复杂Markdown结构
markdown_text = """
# 📊 数据报告
## 📈 统计信息
- 用户数量: **1,234**
- 消息总数: **56,789**
- 活跃度: **98.5%**
## 🔗 相关链接
[官方文档](https://example.com)
> 💡 **提示**: 这是一个引用块
"""
message = MessageBuilder.markdown(markdown_text)
构建图片消息:
# 网络图片
message = MessageBuilder.image(
"https://example.com/image.jpg",
"图片描述文字"
)
# 本地图片
message = MessageBuilder.image(
"/local/path/image.png",
"本地图片说明"
)
# 只有图片,无文字说明
message = MessageBuilder.image("https://example.com/photo.jpg")
# 自动上传网络图片
message = MessageBuilder.image(
"https://example.com/image.jpg",
"网络图片",
auto_upload=True # 自动上传到QQ服务器
)
构建视频消息:
# 网络视频
message = MessageBuilder.video(
"https://example.com/video.mp4",
"视频描述文字"
)
# 本地视频
message = MessageBuilder.video(
"/local/path/video.mp4",
"本地视频说明",
auto_upload=True
)
# 只有视频,无文字说明
message = MessageBuilder.video("https://example.com/video.mp4")
构建语音消息:
# 网络语音
message = MessageBuilder.voice(
"https://example.com/voice.silk",
"语音描述文字"
)
# 本地语音
message = MessageBuilder.voice(
"/local/path/voice.silk",
"本地语音说明",
auto_upload=True
)
# 只有语音,无文字说明
message = MessageBuilder.voice("https://example.com/voice.silk")
构建文件消息(注意:文件类型暂不开放):
# 网络文件
message = MessageBuilder.file(
"https://example.com/document.pdf",
"文件描述文字"
)
# 本地文件
message = MessageBuilder.file(
"/local/path/document.pdf",
"本地文件说明",
auto_upload=True
)
# 注意:根据QQ官方文档,文件类型暂不开放使用
构建Embed消息:
# 基础Embed
message = MessageBuilder.embed(
title="数据报告",
description="详细的数据分析",
color=0x00ff00 # 绿色
)
# 带字段的Embed
fields = [
{'name': '用户数', 'value': '1,234'},
{'name': '活跃度', 'value': '98.5%'}
]
message = MessageBuilder.embed(
title="系统状态",
description="运行状态良好",
fields=fields,
color=0x0099ff, # 蓝色
thumbnail="https://example.com/icon.png"
)
构建文卡消息(Ark模板23):
# 基础文卡
message = MessageBuilder.text_card(
text="这是文卡的主要内容",
description="文卡描述",
prompt="提示文字"
)
# 带链接的文卡
message = MessageBuilder.text_card(
text="点击查看详情",
description="重要通知",
prompt="点击链接了解更多",
link="https://example.com"
)
构建带链接按钮的文卡消息:
message = MessageBuilder.text_card_link(
text="欢迎使用我们的服务!",
button_text="🔗 访问官网",
button_url="https://example.com",
description="服务介绍",
prompt="点击按钮访问"
)
构建链接卡片消息(Ark模板24):
message = MessageBuilder.link_card(
title="精彩文章推荐",
description="这是一篇关于技术发展的深度文章",
url="https://example.com/article",
cover_image="https://example.com/cover.jpg"
)
构建小卡片消息(Ark模板34):
message = MessageBuilder.small_card(
title="系统通知",
subtitle="您有新的消息待处理",
preview_image="https://example.com/preview.jpg",
icon_image="https://example.com/icon.png",
url="https://example.com/notifications"
)
构建大图消息(Ark模板37):
message = MessageBuilder.large_image(
title="精美图片",
subtitle="高清壁纸推荐",
image_url="https://example.com/wallpaper.jpg",
prompt="点击查看大图"
)
构建带按钮的卡片消息:
buttons = [
{'text': '确认', 'data': 'confirm'},
{'text': '取消', 'data': 'cancel'},
{'text': '帮助', 'data': 'help'}
]
message = MessageBuilder.button_card(
title="操作确认",
content="请选择您要执行的操作",
buttons=buttons
)
def handle_command_with_validation(self, args):
try:
if not args:
return {
'response': MessageBuilder.text('❌ 缺少必要参数'),
'handled': True
}
# 处理逻辑...
result = self.process_command(args)
return {
'response': MessageBuilder.text(f'✅ 处理成功: {result}'),
'handled': True
}
except Exception as e:
return {
'response': MessageBuilder.text(f'❌ 处理失败: {str(e)}'),
'handled': True
}
def handle_dynamic_response(self, message_data):
content = message_data.get('content', '')
if '/help' in content:
# 帮助信息用Markdown格式
help_text = self.generate_help_markdown()
return {
'response': MessageBuilder.markdown(help_text),
'handled': True
}
elif '/image' in content:
# 图片命令
image_url = self.get_random_image()
return {
'response': MessageBuilder.image(image_url, "随机图片"),
'handled': True
}
else:
# 普通回复用文本
return {
'response': MessageBuilder.text("收到你的消息了!"),
'handled': True
}
插件可以注册命令信息,用于展示和帮助系统:
# 注册命令信息
self.register_command_info(command, description, usage)
# 参数说明:
# command: 命令名称(不含/前缀)
# description: 命令描述
# usage: 使用方法(可选)
# 示例
self.register_command_info('echo', '重复发送的内容', '/echo <内容>')
self.register_command_info('help', '显示帮助信息', '/help [命令名]')
# 获取插件的所有命令信息
commands = self.get_commands_info()
# 返回格式:
{
'echo': {
'description': '重复发送的内容',
'usage': '/echo <内容>'
},
'help': {
'description': '显示帮助信息',
'usage': '/help [命令名]'
}
}
message_received Hookhandle_message_hook方法被调用# 处理了消息,返回响应
return {
'response': '回复内容',
'handled': True
}
# 没有处理消息,让其他插件处理
return {'handled': False}
# 处理了消息,但不回复
return {'handled': True}
"""
多消息回复示例插件 - 展示新的多消息Hook功能
"""
from Core.plugin.base import BasePlugin
from Core.logging.file_logger import log_info
from Core.message.message_builder import MessageBuilder
class Plugin(BasePlugin):
"""多消息回复示例插件"""
def __init__(self):
super().__init__()
self.name = "MultiMessagePlugin"
self.version = "1.0.0"
self.description = "展示多消息回复功能的示例插件"
self.author = "Plugin Developer"
# 注册命令信息
self.register_command_info('report', '生成多格式报告', '/report [类型]')
self.register_command_info('tutorial', '显示教程', '/tutorial')
self.register_command_info('status', '系统状态检查', '/status')
self.hooks = {
'message_received': [self.handle_message_hook]
}
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook - 展示多消息功能"""
try:
content = message_data.get('content', '').strip()
if content.startswith('/'):
return self._handle_command(content, bot_id)
return {'handled': False}
except Exception as e:
log_info(bot_id or 0, f"{self.name}插件处理消息异常: {e}", "PLUGIN_ERROR")
return {'handled': False}
def _handle_command(self, content, bot_id=None):
"""处理命令"""
parts = content[1:].split()
if not parts:
return {'handled': False}
command = parts[0].lower()
args = parts[1:] if len(parts) > 1 else []
if command == 'report':
return self.handle_report_command(args)
elif command == 'tutorial':
return self.handle_tutorial_command()
elif command == 'status':
return self.handle_status_command()
return {'handled': False}
def handle_report_command(self, args):
"""生成多格式报告 - 多消息回复示例"""
report_type = args[0] if args else 'basic'
# 🆕 返回多条不同类型的消息
return {
'response': [
# 1. 文本消息 - 报告标题
MessageBuilder.text(f'📊 正在生成 {report_type} 报告...'),
# 2. 文卡消息 - 报告内容
MessageBuilder.text_card(
text=f'报告类型:{report_type}\n生成时间:2025-07-06 01:00:00\n数据来源:系统数据库\n\n主要指标:\n• 用户活跃度:95.2%\n• 系统性能:优秀\n• 错误率:0.1%',
description=f'{report_type.title()} 数据报告',
prompt='详细报告数据'
),
# 3. Markdown消息 - 详细分析
MessageBuilder.markdown(f'''
# 📈 {report_type.title()} 报告分析
## 🔍 关键发现
- **性能表现**: 系统运行稳定
- **用户反馈**: 满意度较高
- **改进建议**: 继续优化响应速度
## 📋 数据摘要
| 指标 | 数值 | 状态 |
|------|------|------|
| 响应时间 | 120ms | ✅ 优秀 |
| 成功率 | 99.9% | ✅ 优秀 |
| 用户满意度 | 4.8/5 | ✅ 优秀 |
> 💡 **建议**: 继续保持当前优化策略
'''),
# 4. 图片消息 - 图表展示
MessageBuilder.image(
'https://via.placeholder.com/600x400/4CAF50/white?text=Report+Chart',
'📊 报告图表'
),
# 5. 文本消息 - 完成提示
MessageBuilder.text('✅ 报告生成完成!如需更多详细信息,请联系管理员。')
],
'handled': True
}
def handle_tutorial_command(self):
"""显示教程 - 多消息教学示例"""
return {
'response': [
# 欢迎消息
MessageBuilder.text('🎓 欢迎来到多消息插件教程!'),
# 教程步骤1
MessageBuilder.text_card(
text='步骤1:了解多消息功能\n\n多消息功能允许插件在一次回复中发送多条不同类型的消息,包括文本、图片、卡片等。',
description='教程 - 第1步',
prompt='多消息基础概念'
),
# 教程步骤2
MessageBuilder.text_card(
text='步骤2:使用方法\n\n在Hook返回值中,将response设置为MessageBuilder对象的数组即可实现多消息发送。',
description='教程 - 第2步',
prompt='实现方法说明'
),
# 代码示例
MessageBuilder.markdown('''
# 💻 代码示例
```python
return {
'response': [
MessageBuilder.text('第一条消息'),
MessageBuilder.text_card('第二条卡片消息'),
MessageBuilder.image('图片URL', '第三条图片')
],
'handled': True
}
支持的消息类型: - 📝 文本消息 (msg_type: 0) - 🎨 Markdown消息 (msg_type: 2) - 🖼️ 图片消息 (msg_type: 7) - 📹 视频消息 (msg_type: 7) - 🎵 语音消息 (msg_type: 7) - 📁 文件消息 (msg_type: 7, 暂不开放) - 📊 Embed消息 (msg_type: 4) - 📋 文卡消息 (Ark模板23) - 🔗 链接卡片 (Ark模板24) - 🎯 小卡片 (Ark模板34) - 🖼️ 大图消息 (Ark模板37) - 🔘 按钮消息 (需要申请) '''),
# 结束消息
MessageBuilder.text('🎉 教程完成!现在你可以开始使用多消息功能了。')
],
'handled': True
}
def handle_status_command(self):
"""系统状态检查 - 实用多消息示例"""
import datetime
import random
# 模拟系统数据
cpu_usage = random.randint(10, 80)
memory_usage = random.randint(30, 90)
disk_usage = random.randint(20, 70)
return {
'response': [
# 状态标题
MessageBuilder.text('🔍 系统状态检查中...'),
# 系统概览卡片
MessageBuilder.text_card(
text=f'系统运行时间:72小时\n最后检查:{datetime.datetime.now().strftime("%H:%M:%S")}\n状态:运行正常',
description='系统概览',
prompt='基本系统信息'
),
# 详细状态报告
MessageBuilder.markdown(f'''
# 建议和警告
MessageBuilder.text_card(
text='💡 系统建议:\n\n• 定期清理临时文件\n• 监控内存使用情况\n• 保持系统更新\n• 定期备份重要数据',
description='维护建议',
prompt='系统优化建议'
),
# 完成消息
MessageBuilder.text('✅ 系统状态检查完成!所有服务运行正常。')
],
'handled': True
}
### 命令处理插件
```python
from Core.message.message_builder import MessageBuilder
class Plugin(BasePlugin):
def __init__(self):
super().__init__()
self.name = "CommandPlugin"
self.version = "1.0.0"
self.description = "命令处理示例插件"
# 注册命令信息(用于展示和帮助)
self.register_command_info('weather', '查询天气', '/weather [城市]')
self.register_command_info('time', '获取时间', '/time')
self.register_command_info('joke', '讲个笑话', '/joke')
# 命令处理器
self.command_handlers = {
'weather': self.handle_weather,
'time': self.handle_time,
'joke': self.handle_joke
}
self.hooks = {
'message_received': [self.handle_message_hook]
}
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook"""
content = message_data.get('content', '').strip()
# 检查是否是命令
if content.startswith('/'):
return self._handle_command(content, bot_id)
return {'handled': False}
def _handle_command(self, content, bot_id=None):
"""处理命令"""
# 解析命令
parts = content[1:].split()
if not parts:
return {'handled': False}
command = parts[0].lower()
args = parts[1:] if len(parts) > 1 else []
# 检查是否支持该命令
if command in self.command_handlers:
try:
handler = self.command_handlers[command]
response = handler(args)
return {
'response': response,
'handled': True
}
except Exception as e:
return {
'response': f"命令执行出错: {str(e)}",
'handled': True
}
return {'handled': False}
def handle_weather(self, args):
"""处理天气命令"""
city = args[0] if args else "北京"
return MessageBuilder.text(f"🌤️ {city}今天天气晴朗,温度25°C")
def handle_time(self, args):
"""处理时间命令"""
from datetime import datetime
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return MessageBuilder.text(f"🕐 当前时间:{current_time}")
def handle_joke(self, args):
"""处理笑话命令"""
jokes = [
"为什么程序员喜欢黑暗?因为光明会产生bug!",
"程序员的三大美德:懒惰、急躁和傲慢。",
"世界上有10种人:懂二进制的和不懂二进制的。"
]
import random
return MessageBuilder.text(f"😄 {random.choice(jokes)}")
class Plugin(BasePlugin):
def __init__(self):
super().__init__()
self.name = "AdvancedPlugin"
self.version = "1.0.0"
self.description = "完整功能示例插件"
self.author = "Plugin Developer"
# 注册命令信息
self.register_command_info('greet', '智能问候', '/greet [名字]')
self.register_command_info('calc', '简单计算', '/calc <表达式>')
self.register_command_info('status', '插件状态', '/status')
# 命令处理器
self.command_handlers = {
'greet': self.handle_greet,
'calc': self.handle_calc,
'status': self.handle_status
}
self.hooks = {
'message_received': [self.handle_message_hook],
'after_bot_start': [self.on_after_bot_start_hook],
'after_bot_stop': [self.on_after_bot_stop_hook]
}
log_info(0, f"{self.name}插件初始化完成", "PLUGIN_INIT", plugin=self.name)
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook"""
try:
content = message_data.get('content', '').strip()
# 处理命令
if content.startswith('/'):
return self._handle_command(content, bot_id)
# 处理自然语言
return self._handle_natural_language(content, bot_id)
except Exception as e:
log_info(bot_id or 0, f"{self.name}插件处理消息异常: {e}", "PLUGIN_ERROR")
return {'handled': False}
def _handle_command(self, content, bot_id=None):
"""处理命令"""
parts = content[1:].split()
if not parts:
return {'handled': False}
command = parts[0].lower()
args = parts[1:] if len(parts) > 1 else []
if command in self.command_handlers:
try:
handler = self.command_handlers[command]
response = handler(args)
return {
'response': response,
'handled': True
}
except Exception as e:
return {
'response': f"命令执行出错: {str(e)}",
'handled': True
}
return {'handled': False}
def _handle_natural_language(self, content, bot_id=None):
"""处理自然语言"""
content_lower = content.lower()
# 问候语处理
if any(word in content_lower for word in ['你好', 'hello', 'hi']):
return {
'response': MessageBuilder.text(f'你好!我是{self.name}插件 👋\n发送 /help 查看可用命令'),
'handled': True
}
return {'handled': False}
def handle_greet(self, args):
"""处理问候命令"""
name = args[0] if args else "朋友"
return MessageBuilder.text(f"你好,{name}!很高兴见到你!😊")
def handle_calc(self, args):
"""处理计算命令"""
if not args:
return MessageBuilder.text("请输入要计算的表达式,例如:/calc 1+2*3")
try:
expression = " ".join(args)
# 简单的安全计算(仅支持基本运算)
allowed_chars = set('0123456789+-*/().')
if not all(c in allowed_chars or c.isspace() for c in expression):
return MessageBuilder.text("❌ 只支持基本数学运算符")
result = eval(expression)
return MessageBuilder.text(f"📊 {expression} = {result}")
except Exception as e:
return MessageBuilder.text(f"❌ 计算错误: {str(e)}")
def handle_status(self, args):
"""处理状态命令"""
commands = self.get_commands_info()
status_text = f"🔌 {self.name} 状态信息\n\n"
status_text += f"版本: {self.version}\n"
status_text += f"作者: {self.author}\n"
status_text += f"支持命令: {len(commands)}个\n\n"
status_text += "可用命令:\n"
for cmd, info in commands.items():
status_text += f"• /{cmd} - {info['description']}\n"
return MessageBuilder.text(status_text)
def on_after_bot_start_hook(self, bot_id, bot_config):
"""机器人启动后Hook"""
return {'message': f'{self.name}插件已为机器人 {bot_id} 准备就绪'}
def on_after_bot_stop_hook(self, bot_id):
"""机器人停止后Hook"""
return {'message': f'{self.name}插件已为机器人 {bot_id} 清理资源'}
from Core.message.message_builder import MessageBuilder
class Plugin(BasePlugin):
def __init__(self):
super().__init__()
self.name = "NLPPlugin"
self.version = "1.0.0"
self.description = "自然语言处理插件"
self.hooks = {
'message_received': [self.handle_message_hook]
}
def handle_message_hook(self, message_data, bot_id=None):
"""处理自然语言消息"""
content = message_data.get('content', '').strip().lower()
# 情感分析
if any(word in content for word in ['开心', '高兴', '快乐']):
return {
'response': MessageBuilder.text('😊 看起来你心情不错呢!'),
'handled': True
}
if any(word in content for word in ['难过', '伤心', '沮丧']):
return {
'response': MessageBuilder.text('😔 别难过,一切都会好起来的!'),
'handled': True
}
# 问候语处理
if any(word in content for word in ['早上好', '晚上好', '下午好']):
return {
'response': MessageBuilder.text('你好!祝你今天过得愉快!'),
'handled': True
}
return {'handled': False}
import json
import os
from Core.message.message_builder import MessageBuilder
class Plugin(BasePlugin):
def __init__(self):
super().__init__()
self.name = "DataPlugin"
self.version = "1.0.0"
self.description = "数据存储示例插件"
# 数据文件路径
self.data_file = os.path.join('Plugins', 'data_plugin', 'data.json')
self.ensure_data_file()
self.hooks = {
'message_received': [self.handle_message_hook]
}
def ensure_data_file(self):
"""确保数据文件存在"""
os.makedirs(os.path.dirname(self.data_file), exist_ok=True)
if not os.path.exists(self.data_file):
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump({}, f)
def load_data(self):
"""加载数据"""
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {}
def save_data(self, data):
"""保存数据"""
try:
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except:
return False
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息"""
content = message_data.get('content', '').strip()
user_id = self._get_user_id(message_data)
if content.startswith('/save '):
# 保存数据
text = content[6:]
data = self.load_data()
if user_id not in data:
data[user_id] = []
data[user_id].append(text)
if self.save_data(data):
return {
'response': MessageBuilder.text(f'✅ 已保存:{text}'),
'handled': True
}
else:
return {
'response': MessageBuilder.text('❌ 保存失败'),
'handled': True
}
elif content == '/list':
# 列出数据
data = self.load_data()
user_data = data.get(user_id, [])
if user_data:
response = "📋 你的保存记录:\n" + "\n".join(f"{i + 1}. {item}" for i, item in enumerate(user_data))
else:
response = "📋 你还没有保存任何记录"
return {
'response': MessageBuilder.text(response),
'handled': True
}
return {'handled': False}
def _get_user_id(self, message_data):
"""获取用户ID"""
if 'author' in message_data:
author = message_data['author']
if isinstance(author, dict):
return author.get('user_openid') or author.get('id') or 'unknown'
return 'unknown'
# ✅ 适合使用多消息的场景
def handle_complex_query(self):
return {
'response': [
MessageBuilder.text('🔍 查询中...'), # 1. 状态提示
MessageBuilder.text_card('查询结果...'), # 2. 主要内容
MessageBuilder.markdown('## 详细分析...'), # 3. 补充信息
MessageBuilder.text('✅ 查询完成') # 4. 完成提示
],
'handled': True
}
# ❌ 不建议的使用方式
def handle_simple_hello(self):
return {
'response': [
MessageBuilder.text('你好'),
MessageBuilder.text('!'),
MessageBuilder.text('欢迎使用')
], # 过度拆分简单消息
'handled': True
}
# ✅ 好的组织方式:逻辑清晰,层次分明
def handle_report_command(self):
return {
'response': [
# 1. 开始提示
MessageBuilder.text('📊 生成报告中...'),
# 2. 主要内容(使用合适的消息类型)
MessageBuilder.text_card(
text='报告数据...',
description='数据报告',
prompt='详细信息'
),
# 3. 补充信息(如果需要)
MessageBuilder.markdown('## 分析结果\n...'),
# 4. 结束提示
MessageBuilder.text('✅ 报告生成完成')
],
'handled': True
}
# 根据内容选择合适的消息类型
def choose_message_type_example(self):
return {
'response': [
# 简单文本 → text()
MessageBuilder.text('操作开始'),
# 结构化数据 → text_card()
MessageBuilder.text_card(
text='用户信息\n姓名:张三\n等级:VIP',
description='用户资料',
prompt='详细信息'
),
# 复杂格式 → markdown()
MessageBuilder.markdown('''
# 数据分析
## 统计结果
- 项目1: 85%
- 项目2: 92%
'''),
# 图片展示 → image()
MessageBuilder.image('chart.jpg', '统计图表'),
# 状态提示 → text()
MessageBuilder.text('✅ 分析完成')
],
'handled': True
}
# ✅ 控制消息数量
def optimized_multi_message(self):
# 建议:单次回复不超过5条消息
return {
'response': [
MessageBuilder.text('开始处理'),
MessageBuilder.text_card('主要内容'),
MessageBuilder.text('处理完成')
], # 3条消息,合理数量
'handled': True
}
# ❌ 避免过多消息
def too_many_messages(self):
return {
'response': [
MessageBuilder.text(f'消息{i}') for i in range(20)
], # 20条消息,可能影响用户体验
'handled': True
}
# ✅ 好的做法
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook"""
try:
content = message_data.get('content', '').strip()
if not content:
return {'handled': False}
# 具体处理逻辑
if content == '/hello':
return {
'response': MessageBuilder.text('Hello World!'),
'handled': True
}
return {'handled': False}
except Exception as e:
log_info(bot_id or 0, f"插件处理异常: {e}", "PLUGIN_ERROR")
return {'handled': False}
# ❌ 避免的做法
def handle_message_hook(self, message_data, bot_id=None):
content = message_data['content'] # 可能KeyError
# 没有异常处理
return content.upper() # 错误的返回格式
from Core.logging.file_logger import log_info, log_error, log_warn
# 记录重要操作
log_info(bot_id, "插件执行成功", "PLUGIN_SUCCESS", operation="command_execute")
# 记录错误
log_error(bot_id, f"插件执行失败: {e}", "PLUGIN_ERROR", error=str(e))
# 记录警告
log_warn(bot_id, "插件配置缺失", "PLUGIN_CONFIG_MISSING")
# config.py
DEFAULT_CONFIG = {
'api_key': '',
'max_requests': 100,
'timeout': 30
}
# __init__.py
import os
from .config import DEFAULT_CONFIG
class Plugin(BasePlugin):
def __init__(self):
super().__init__()
self.config = self.load_config()
def load_config(self):
"""加载配置"""
config = DEFAULT_CONFIG.copy()
# 从环境变量加载
config['api_key'] = os.getenv('MY_PLUGIN_API_KEY', config['api_key'])
return config
插件日志记录在 logs/system/ 目录下:
# 查看今天的系统日志
tail -f logs/system/$(date +%Y-%m-%d).log
# 搜索特定插件的日志
grep "MyPlugin" logs/system/$(date +%Y-%m-%d).log
# 添加调试日志
log_info(bot_id, f"调试信息: {variable}", "DEBUG", data=variable)
# 检查消息数据结构
def handle_message_hook(self, message_data, bot_id=None):
log_info(bot_id, f"收到消息数据: {message_data}", "DEBUG")
# ... 处理逻辑
通过管理界面查看插件状态:
/admin/plugins 查看插件列表我们的混合架构结合了Hook系统的灵活性和传统命令系统的可发现性:
/commands查看所有可用命令register_command_info()用于注册命令信息| 特性 | 传统命令系统 | Hook驱动 | Hook + 命令发现 |
|---|---|---|---|
| 命令处理 | ✅ 统一处理 | ❌ 需要自己解析 | ✅ 自己解析 + 信息注册 |
| 自然语言 | ❌ 不支持 | ✅ 完全支持 | ✅ 完全支持 |
| 命令发现 | ✅ 自动收集 | ❌ 无法发现 | ✅ 主动注册 |
| 灵活性 | ❌ 受限 | ✅ 完全灵活 | ✅ 完全灵活 |
| 管理界面 | ✅ 显示命令 | ❌ 无法显示 | ✅ 显示命令 |
A: 检查以下几点:
__init__.py 文件是否存在Plugin 类是否正确定义A: 确认:
message_received)self.hooksA: 示例代码:
import asyncio
import aiohttp
def handle_message_hook(self, message_data, bot_id=None):
"""处理消息Hook"""
content = message_data.get('content', '').strip()
if content.startswith('/weather'):
# 创建新的事件循环处理异步操作
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
result = loop.run_until_complete(self.get_weather_async())
return {
'response': MessageBuilder.text(result),
'handled': True
}
finally:
loop.close()
return {'handled': False}
async def get_weather_async(self):
"""异步获取天气"""
async with aiohttp.ClientSession() as session:
async with session.get('http://api.weather.com/...') as resp:
data = await resp.json()
return f"天气:{data['weather']}"
A: 使用register_command_info()注册命令信息:
def __init__(self):
super().__init__()
# 注册命令信息
self.register_command_info('mycommand', '我的命令描述', '/mycommand <参数>')
# 在Hook中处理命令
def handle_message_hook(self, message_data, bot_id=None):
content = message_data.get('content', '')
if content.startswith('/mycommand'):
# 处理命令逻辑
return {'response': MessageBuilder.text('命令执行结果'), 'handled': True}
return {'handled': False}
A: 通过Hook系统的自定义事件:
# 插件A:触发自定义事件
class PluginA(BasePlugin):
def trigger_custom_event(self, data):
from Core.bot.manager import get_bot_manager
bot_manager = get_bot_manager()
bot_manager.plugin_manager.trigger_hook('custom_event', data)
# 插件B:监听自定义事件
class PluginB(BasePlugin):
def __init__(self):
super().__init__()
self.hooks = {
'custom_event': [self.handle_custom_event]
}
def handle_custom_event(self, data):
# 处理来自其他插件的数据
return {'message': f'收到数据: {data}'}
A:
A: 在Hook返回值中使用消息数组:
def handle_message_hook(self, message_data, bot_id=None):
if message_data.get('content') == '/multi':
return {
'response': [
MessageBuilder.text('第一条消息'),
MessageBuilder.text_card('第二条卡片消息'),
MessageBuilder.text('第三条消息')
],
'handled': True
}
A: 技术上没有硬性限制,但建议:
A: 完全可以!这正是多消息功能的优势:
return {
'response': [
MessageBuilder.text('📊 数据查询结果'), # 文本
MessageBuilder.text_card('详细数据...'), # 卡片
MessageBuilder.markdown('## 分析\n...'), # Markdown
MessageBuilder.image('chart.jpg', '图表'), # 图片
MessageBuilder.text('✅ 查询完成') # 文本
],
'handled': True
}
A: 完全兼容!现有插件无需修改:
# 旧方式(仍然支持)
return {
'response': MessageBuilder.text('单条消息'),
'handled': True
}
# 新方式(多消息)
return {
'response': [
MessageBuilder.text('第一条'),
MessageBuilder.text('第二条')
],
'handled': True
}
🎉 开始创建你的第一个插件吧! 如有问题,请查看现有插件代码或联系开发团队。