结构调整

视频解析多图/多媒体结构 消息体适配
This commit is contained in:
2026-09-08 14:25:32 +08:00
parent 30899688a7
commit 131b92b319
72 changed files with 433 additions and 186 deletions
+416
View File
@@ -0,0 +1,416 @@
# NoneBot2 + OneBot V11 完整能力清单
> 本文档整理 NoneBot2 框架和 OneBot V11 协议的全部原生能力,
> 用于指导 HexiCore 封装层的设计——只封装原生不方便用的部分。
---
# 一、NoneBot2 框架能力
## 1. 事件响应器(Matcher)
| 创建方式 | 用途 |
|---|---|
| `on_command(cmd, aliases)` | 命令匹配(最常用) |
| `on_startswith(prefix)` | 前缀匹配 |
| `on_endswith(suffix)` | 后缀匹配 |
| `on_fullmatch(text)` | 完全匹配 |
| `on_keyword(words)` | 关键词匹配 |
| `on_regex(pattern)` | 正则匹配 |
| `on_message()` | 所有消息 |
| `on_notice()` | 通知事件 |
| `on_request()` | 请求事件 |
| `on_type(event_types)` | 指定事件类型 |
**Matcher 生命周期方法:**
```python
matcher.handle() # 注册处理函数
matcher.got(key, prompt) # 等待用户输入
matcher.receive("id") # 等待下一条消息
matcher.send(msg) # 发送消息
matcher.finish(msg) # 发送并结束
matcher.reject(msg) # 拒绝输入,重新等待
matcher.pause() # 暂停,等待下一条消息
matcher.stop_propagation()# 阻止后续匹配器
```
**内置权限:**
```python
from nonebot.permission import SUPERUSER, GROUP_ADMIN, GROUP_OWNER, GROUP, PRIVATE
```
**内置规则:**
```python
from nonebot.rule import to_me, is_type, command, keyword, startswith, endswith, fullmatch, regex
```
---
## 2. 依赖注入(DI)
**类型注入(直接写类型注解即可):**
```python
async def handler(
bot: Bot,
event: Event,
state: T_State,
matcher: Matcher,
): ...
```
**参数依赖(from nonebot.params):**
| 依赖 | 返回值 |
|---|---|
| `CommandArg()` | 命令参数 `Message` |
| `Command()` | 命令名 `tuple[str, ...]` |
| `RawCommand()` | 原始命令文本 |
| `CommandStart()` | 命令前缀 |
| `EventMessage()` | 事件消息 `Message` |
| `EventPlainText()` | 纯文本 |
| `EventToMe()` | 是否 @ 机器人 `bool` |
| `Arg(key)` | `got` 获取的参数 |
| `ArgStr(key)` | `got` 参数的字符串 |
| `ArgPlainText(key)` | `got` 参数的纯文本 |
| `RegexGroup()` | 正则捕获组 |
| `RegexStr()` | 正则匹配文本 |
---
## 3. 消息系统
### Message 类(List[MessageSegment])
```python
msg.extract_plain_text() # 提取纯文本
msg.has("image") # 是否包含某类型
msg.only("text") # 是否只有某类型
msg["text"] # 过滤出所有文本段
msg["text", 0] # 第一个文本段
msg.include("text", "image") # 只保留指定类型
msg.exclude("image") # 排除指定类型
msg.count("image") # 计数
msg.index("image") # 索引
msg + "text" # 拼接
Message.template("{} {}").format(a, b) # 模板
```
### OneBot V11 MessageSegment
```python
MessageSegment.text("hello") # 文本
MessageSegment.image(file) # 图片(URL/路径/base64)
MessageSegment.record(file) # 语音
MessageSegment.video(file) # 视频
MessageSegment.at(user_id) # @某人
MessageSegment.at_all() # @全体
MessageSegment.reply(msg_id) # 回复
MessageSegment.face(id) # QQ表情
MessageSegment.poke(type, id) # 戳一戳
MessageSegment.forward(id) # 转发消息
MessageSegment.json(data) # JSON卡片
MessageSegment.xml(data) # XML卡片
MessageSegment.share(url, title) # 链接分享
MessageSegment.music(type, id) # 音乐卡片
MessageSegment.location(lat, lon) # 位置
```
---
## 4. UniMessage(跨平台消息,nonebot-plugin-alconna)
```python
UniMessage.text("hello") # 文本
UniMessage.at("123456") # @某人
UniMessage.at_all() # @全体
UniMessage.image(url="...") # 图片
UniMessage.audio(url="...") # 音频
UniMessage.voice(url="...") # 语音
UniMessage.video(url="...") # 视频
UniMessage.file("id") # 文件
UniMessage.reply("msg_id") # 回复
UniMessage.emoji("id") # 表情
```
**发送与操作:**
```python
await msg.send() # 发送
await msg.send(at_sender=True) # @发送者
await msg.send(reply_to=True) # 回复原消息
await msg.finish() # 发送并结束
receipt = await msg.send() # 获取回执
await receipt.recall(delay=5) # 5秒后撤回
await receipt.edit(UniMessage.text("新内容")) # 编辑
await receipt.reaction("thumbsup") # 添加表情回应
```
**序列化:**
```python
data = msg.dump() # 存储
msg = UniMessage.load(data) # 还原
```
---
# 二、OneBot V11 协议能力
## 1. 消息类 API
| API | 参数 | 说明 |
|---|---|---|
| `send_msg` | `message_type`, `user_id`/`group_id`, `message` | 通用发送 |
| `send_private_msg` | `user_id`, `message` | 私聊发送 |
| `send_group_msg` | `group_id`, `message` | 群聊发送 |
| `delete_msg` | `message_id` | 撤回消息 |
| `get_msg` | `message_id` | 获取消息详情 |
| `get_forward_msg` | `id` | 获取转发消息内容 |
## 2. 群管理 API
| API | 参数 | 说明 |
|---|---|---|
| `set_group_kick` | `group_id`, `user_id`, `reject_add_request` | 踢出成员 |
| `set_group_ban` | `group_id`, `user_id`, `duration` | 禁言(0=解除) |
| `set_group_anonymous_ban` | `group_id`, `anonymous_flag`, `duration` | 禁言匿名 |
| `set_group_whole_ban` | `group_id`, `enable` | 全员禁言 |
| `set_group_admin` | `group_id`, `user_id`, `enable` | 设置/取消管理员 |
| `set_group_card` | `group_id`, `user_id`, `card` | 修改群名片 |
| `set_group_name` | `group_id`, `group_name` | 修改群名 |
| `set_group_leave` | `group_id`, `is_dismiss` | 退群/解散 |
| `set_group_special_title` | `group_id`, `user_id`, `special_title` | 设置群头衔 |
| `set_group_anonymous` | `group_id`, `enable` | 开关匿名聊天 |
## 3. 请求处理 API
| API | 参数 | 说明 |
|---|---|---|
| `set_friend_add_request` | `flag`, `approve`, `remark` | 好友申请 |
| `set_group_add_request` | `flag`, `sub_type`, `approve`, `reason` | 加群/邀请申请 |
## 4. 信息查询 API
| API | 参数 | 说明 |
|---|---|---|
| `get_login_info` | — | 获取登录信息 |
| `get_stranger_info` | `user_id`, `no_cache` | 获取陌生人信息 |
| `get_friend_list` | — | 获取好友列表 |
| `get_group_info` | `group_id`, `no_cache` | 获取群信息 |
| `get_group_list` | — | 获取群列表 |
| `get_group_member_info` | `group_id`, `user_id`, `no_cache` | 获取群成员信息 |
| `get_group_member_list` | `group_id` | 获取群成员列表 |
| `get_group_honor_info` | `group_id`, `type` | 获取群荣耀信息 |
## 5. 社交 API
| API | 参数 | 说明 |
|---|---|---|
| `send_like` | `user_id`, `times` | 点赞(最多10次/天) |
## 6. 媒体 API
| API | 参数 | 说明 |
|---|---|---|
| `get_image` | `file` | 获取图片文件 |
| `get_record` | `file`, `out_format` | 获取语音文件 |
| `can_send_image` | — | 检查能否发图 |
| `can_send_record` | — | 检查能否发语音 |
## 7. 系统 API
| API | 参数 | 说明 |
|---|---|---|
| `get_status` | — | 运行状态 |
| `get_version_info` | — | 版本信息 |
| `set_restart` | `delay` | 重启 |
| `clean_cache` | — | 清理缓存 |
---
# 三、OneBot V11 事件类型
## 消息事件
| 事件类 | 关键字段 |
|---|---|
| `GroupMessageEvent` | `group_id`, `user_id`, `message_id`, `message`, `sender` |
| `PrivateMessageEvent` | `user_id`, `message_id`, `message`, `sender` |
**GroupMessageEvent.sender 字段:**
```python
sender.user_id # QQ号
sender.nickname # 昵称
sender.card # 群名片
sender.role # "owner" / "admin" / "member"
sender.title # 群头衔
sender.sex # 性别
sender.age # 年龄
sender.area # 地区
sender.level # 等级
```
## 通知事件
| 事件类 | 关键字段 | 说明 |
|---|---|---|
| `PokeNotifyEvent` | `group_id`, `user_id`, `target_id` | 戳一戳 |
| `GroupIncreaseNoticeEvent` | `group_id`, `user_id`, `operator_id` | 成员加入 |
| `GroupDecreaseNoticeEvent` | `group_id`, `user_id`, `operator_id` | 成员离开 |
| `GroupBanNoticeEvent` | `group_id`, `user_id`, `operator_id`, `duration` | 禁言 |
| `GroupAdminNoticeEvent` | `group_id`, `user_id` | 管理员变动 |
| `GroupRecallNoticeEvent` | `group_id`, `user_id`, `operator_id`, `message_id` | 群消息撤回 |
| `FriendRecallNoticeEvent` | `user_id`, `message_id` | 私聊消息撤回 |
| `FriendAddNoticeEvent` | `user_id` | 好友添加 |
| `GroupUploadNoticeEvent` | `group_id`, `user_id`, `file` | 文件上传 |
| `GroupNotifyEvent` | `sub_type="lucky_king"` | 红包运气王 |
| `GroupNotifyEvent` | `sub_type="honor"` | 荣誉变更 |
## 请求事件
| 事件类 | 关键字段 | 说明 |
|---|---|---|
| `FriendRequestEvent` | `user_id`, `comment`, `flag` | 好友申请 |
| `GroupRequestEvent` | `group_id`, `user_id`, `comment`, `flag`, `sub_type` | 加群/邀请申请 |
## 元事件
| 事件类 | 说明 |
|---|---|
| `MetaEvent` (lifecycle) | 生命周期(enable/disable/connect) |
| `MetaEvent` (heartbeat) | 心跳 |
---
# 四、HexiCore 封装建议
## 已有原生能力(无需封装,直接用)
| 能力 | 原生用法 |
|---|---|
| 发消息 | `UniMessage.text("hello").send()` |
| 发图片 | `UniMessage.image(url="...").send()` |
| @某人 | `UniMessage.at("123").send()` |
| 回复消息 | `UniMessage.reply("msg_id").send()` |
| 撤回消息 | `bot.delete_msg(message_id=...)` |
| 禁言 | `bot.set_group_ban(group_id=..., user_id=..., duration=...)` |
| 踢人 | `bot.set_group_kick(group_id=..., user_id=...)` |
| 群名片 | `bot.set_group_card(group_id=..., user_id=..., card=...)` |
| 管理员 | `bot.set_group_admin(group_id=..., user_id=..., enable=...)` |
| 群头衔 | `bot.set_group_special_title(group_id=..., user_id=..., title=...)` |
| 好友申请 | `bot.set_friend_add_request(flag=..., approve=...)` |
| 加群申请 | `bot.set_group_add_request(flag=..., sub_type=..., approve=...)` |
| 判断群/私聊 | `isinstance(event, GroupMessageEvent)` |
| 获取发送者 | `event.sender.user_id` / `event.sender.nickname` |
| 获取群号 | `event.group_id` |
| 获取消息ID | `event.message_id` |
| 判断管理员 | `event.sender.role in ("admin", "owner")` |
| 判断超级用户 | `str(event.user_id) in driver.config.superusers` |
| 遍历消息段 | `for seg in event.message: ...` |
| 获取纯文本 | `event.get_plaintext()` |
## 值得封装(原生用起来麻烦)
### 1. 戳一戳(Poke)
```python
# 原生:需要知道 API 非标准
await bot.call_api("send_poke", group_id=group_id, user_id=user_id)
# HexiCore 封装:简化为
await hexi.poke(group_id, user_id)
```
### 2. 合并转发消息
```python
# 原生:需要手动构建 node 结构
nodes = [
{"type": "node", "data": {"user_id": "123", "nickname": "name", "content": [seg]}},
...
]
await bot.call_api("send_group_forward_msg", group_id=group_id, message=nodes)
# HexiCore 封装:链式构建
forward = hexi.forward()
forward.add("123", "name", UniMessage.text("内容"))
forward.add("456", "name2", UniMessage.image(url="..."))
await forward.send(group_id)
```
### 3. 消息加精 / 取消加精
```python
# 原生:API 名称不直观
await bot.call_api("set_msg_essence", message_id=msg_id)
await bot.call_api("delete_msg_essence", message_id=msg_id)
# HexiCore 封装
await hexi.essence(msg_id) # 加精
await hexi.unessence(msg_id) # 取消
```
### 4. 获取 At 用户列表
```python
# 原生:需要遍历
at_users = [seg.data["qq"] for seg in event.message if seg.type == "at"]
# HexiCore 封装
users = hexi.get_at_users(event)
```
### 5. 是否好友 / 是否群成员
```python
# 原生:需要调用 API + 异常处理
try:
await bot.get_stranger_info(user_id=user_id)
is_friend = True
except:
is_friend = False
# HexiCore 封装
is_friend = await hexi.is_friend(user_id)
is_member = await hexi.is_member(group_id, user_id)
```
### 6. 权限推断(可发送/可撤回/可禁言等)
```python
# 原生:没有直接 API,需要根据身份推断
role = event.sender.role
can_ban = role in ("admin", "owner") # 但还需要检查机器人自身是否是管理员
# HexiCore 封装
can_ban = await hexi.can_ban(group_id, user_id) # 检查目标是否可被禁言
can_kick = await hexi.can_kick(group_id, user_id) # 检查目标是否可被踢
```
### 7. 获取回复的原始消息
```python
# 原生:event.reply 只有 message_id,需要再调 API 获取内容
reply_msg = await bot.get_msg(message_id=event.reply.message_id)
# HexiCore 封装
reply_content = hexi.get_reply_content(event) # 直接返回 Message 对象
```
### 8. 获取消息来源(群号/私聊)
```python
# 原生:需要类型判断 + 字段访问
if isinstance(event, GroupMessageEvent):
source = event.group_id
elif isinstance(event, PrivateMessageEvent):
source = event.user_id
# HexiCore 封装
source = hexi.get_source(event) # 统一返回
```
---
## 总结:HexiCore 定位
```
HexiCore = 原生能力的便利封装层
目标:让业务层用一行代码完成需要写 3-5 行的操作
原则:
1. 不重复造轮子——原生好用的直接用
2. 封装复杂 API 调用——简化参数、统一接口
3. 提供便捷判断方法——省去类型检查和异常处理
4. 保持轻量——只做薄封装,不改变底层行为
```
+156
View File
@@ -0,0 +1,156 @@
# HexiCore 能力清单(精简版)
> **设计目标**
>
> HexiCore 是原生能力的便利封装层,只封装「原生写起来麻烦」的操作。
> 普通消息发送、构建、解析直接使用 Alconna UniMessage,不重复封装。
---
# 需要封装的能力
## 一、消息操作(简化 API 调用)
| 能力 | 原生写法 | HexiCore 写法 |
|---|---|---|
| 戳一戳 | `bot.call_api("send_poke", group_id=..., user_id=...)` | `await hexi.poke(group_id, user_id)` |
| 消息加精 | `bot.call_api("set_msg_essence", message_id=...)` | `await hexi.essence(msg_id)` |
| 取消加精 | `bot.call_api("delete_msg_essence", message_id=...)` | `await hexi.unessence(msg_id)` |
| 合并转发 | 手动构建 node 结构 | `forward.add(user_id, nickname, content).send(group_id)` |
---
## 二、信息提取(省去遍历/判断)
| 能力 | 原生写法 | HexiCore 写法 |
|---|---|---|
| 获取 At 用户列表 | `[seg.data["qq"] for seg in event.message if seg.type == "at"]` | `hexi.get_at_users(event)` |
| 获取回复内容 | `bot.get_msg(message_id=event.reply.message_id)` | `hexi.get_reply_content(event)` |
| 获取消息来源 | 类型判断 + 字段访问 | `hexi.get_source(event)` |
---
## 三、身份查询(需要 API 调用)
| 能力 | 原生写法 | HexiCore 写法 |
|---|---|---|
| 是否好友 | `bot.get_stranger_info()` + 异常处理 | `await hexi.is_friend(user_id)` |
| 是否群成员 | `bot.get_group_member_info()` + 异常处理 | `await hexi.is_member(group_id, user_id)` |
| 获取群成员信息 | `bot.get_group_member_info()` | `await hexi.get_member_info(group_id, user_id)` |
---
## 四、权限推断(原生无直接 API)
| 能力 | 说明 |
|---|---|
| `hexi.can_ban(group_id, user_id)` | 检查目标是否可被禁言(机器人是管理员 + 目标不是群主) |
| `hexi.can_kick(group_id, user_id)` | 检查目标是否可被踢出 |
| `hexi.can_set_admin(group_id)` | 检查机器人是否有管理员权限 |
| `hexi.is_admin(user_id)` | 判断用户是否为管理员 |
| `hexi.is_owner(user_id)` | 判断用户是否为群主 |
| `hexi.is_superuser(user_id)` | 判断用户是否为超级用户 |
---
## 五、批量操作(省去循环)
| 能力 | 说明 |
|---|---|
| `hexi.ban_multi(group_id, user_ids, duration)` | 批量禁言 |
| `hexi.kick_multi(group_id, user_ids)` | 批量踢出 |
---
# 不需要封装(直接用原生)
| 类别 | 能力 | 原生用法 |
|---|---|---|
| 消息发送 | 文本/图片/语音/视频/文件 | `UniMessage.text/image/record/video/file().send()` |
| 消息发送 | @某人/@全体 | `UniMessage.at()/at_all().send()` |
| 消息发送 | 回复消息 | `UniMessage.reply(msg_id).send()` |
| 消息操作 | 撤回消息 | `bot.delete_msg(message_id=...)` |
| 群管理 | 禁言 | `bot.set_group_ban(group_id=..., user_id=..., duration=...)` |
| 群管理 | 踢人 | `bot.set_group_kick(group_id=..., user_id=...)` |
| 群管理 | 群名片 | `bot.set_group_card(group_id=..., user_id=..., card=...)` |
| 群管理 | 管理员 | `bot.set_group_admin(group_id=..., user_id=..., enable=...)` |
| 群管理 | 群头衔 | `bot.set_group_special_title(group_id=..., user_id=..., title=...)` |
| 群管理 | 群名 | `bot.set_group_name(group_id=..., group_name=...)` |
| 群管理 | 全员禁言 | `bot.set_group_whole_ban(group_id=..., enable=...)` |
| 请求处理 | 好友申请 | `bot.set_friend_add_request(flag=..., approve=...)` |
| 请求处理 | 加群申请 | `bot.set_group_add_request(flag=..., sub_type=..., approve=...)` |
| 事件判断 | 群/私聊消息 | `isinstance(event, GroupMessageEvent)` |
| 事件信息 | 发送者 | `event.sender.user_id` / `event.sender.nickname` |
| 事件信息 | 群号 | `event.group_id` |
| 事件信息 | 消息ID | `event.message_id` |
| 事件信息 | 纯文本 | `event.get_plaintext()` |
| 事件信息 | 消息段遍历 | `for seg in event.message: ...` |
---
# 业务层调用示例
```python
from nonebot_plugin_alconna import UniMessage
# 普通消息 — 直接用 UniMessage
await UniMessage.text("Hello").send()
await UniMessage.image(url="https://...").send()
await UniMessage.at("123456").text("你好").send()
# 平台能力 — 用 HexiCore 封装
await hexi.poke(group_id, user_id) # 戳一戳
await hexi.essence(msg_id) # 加精
await hexi.unessence(msg_id) # 取消加精
# 转发消息 — 链式构建
forward = hexi.forward()
forward.add("123", "Alice", UniMessage.text("消息1"))
forward.add("456", "Bob", UniMessage.image(url="..."))
await forward.send(group_id)
# 信息提取 — 一行搞定
users = hexi.get_at_users(event) # At 用户列表
reply = hexi.get_reply_content(event) # 回复内容
source = hexi.get_source(event) # 消息来源
# 身份查询 — 异常处理已封装
is_friend = await hexi.is_friend(user_id) # 是否好友
is_member = await hexi.is_member(group_id, uid) # 是否群成员
info = await hexi.get_member_info(group_id, uid)# 群成员信息
# 权限推断 — 自动检查机器人权限
if await hexi.can_ban(group_id, user_id):
await bot.set_group_ban(group_id=group_id, user_id=user_id, duration=60)
# 身份判断
if hexi.is_admin(event): # 管理员
if hexi.is_owner(event): # 群主
if hexi.is_superuser(event): # 超级用户
```
---
# 架构设计
```
hexi/core/
├── __init__.py # 插件入口,导出 hexi 对象
├── poke.py # 戳一戳
├── forward.py # 合并转发消息构建器
├── essence.py # 消息加精/取消
├── extract.py # 消息提取(At列表、回复内容、来源)
├── member.py # 身份查询(好友、群成员)
├── permission.py # 权限推断(可禁言、可踢人等)
└── utils.py # 工具函数
```
---
# 设计原则
1. **薄封装** — 每个函数只是对原生 API 的简化调用,不添加额外逻辑
2. **类型安全** — 使用类型注解,配合 Pydantic 校验
3. **异常处理** — 内部处理 API 异常,对外返回布尔值或 None
4. **单一职责** — 每个模块只负责一类能力
5. **可选依赖** — 业务层可以选择用原生 API 或 HexiCore 封装