zhilv af0f6c7ec6 feat(command): 回调响应自动回复到 QQ
- 回调服务器可返回 reply 或 messages 字段,插件自动回复到原消息来源
- reply 为纯文本回复,messages 格式同 /webhook 接口
- 支持通过 group_id/user_id 覆盖回复目标
- 无需回复时返回空 JSON 即可
- 更新 README 文档说明回调响应格式
2026-05-02 19:29:18 +08:00
2026-05-01 21:22:57 +08:00
2026-05-01 21:22:57 +08:00
2026-05-01 22:46:06 +08:00

Webhook Plugin

NcatBot 插件,对外暴露 HTTP 接口,接收外部消息转发至 QQ。

功能特性

  • 发送群消息 / 私聊消息(文本、图片、文件、视频)
  • 批量发送消息,自动组合消息段
  • 文件上传接口,支持本地文件发送
  • API Key 鉴权,未配置时自动生成随机密钥
  • 上传文件自动清理(超过 24 小时删除)
  • 完善的错误处理与重试机制

快速开始

# 安装依赖
uv sync

# 复制环境变量模板
cp .env.example .env

# 编辑 .env 配置(可选,不设置 API_KEY 会自动生成)
vim .env

# 启动 NcatBot
uv run python -m ncatbot

启动后日志会打印 WEBHOOK_API_KEY,未配置时为自动生成的 UUID。

环境变量

变量 必填 默认值 说明
WEBHOOK_API_KEY 自动生成 API 鉴权密钥,未设置时自动生成 UUIDv4
WEBHOOK_HOST 0.0.0.0 监听地址
WEBHOOK_PORT 8081 监听端口
UPLOAD_DIR ./uploads 上传文件保存目录
MAX_UPLOAD_SIZE 20971520 单文件最大字节数(默认 20 MB
ALLOWED_EXTENSIONS 空(不限) 允许的扩展名,逗号分隔,如 jpg,png,pdf
QQ_API_TIMEOUT 10 QQ API 超时秒数
QQ_API_MAX_RETRIES 2 QQ API 失败重试次数
COMMAND_PREFIX # 命令前缀
COMMAND_LENGTH 4 命令名字符数(中文字数)
COMMAND_CALLBACK_URL 空(不监听) 命令匹配后的回调 URL

接口说明

所有接口响应格式统一:

// 成功
{"code": 0, "msg": "ok", "data": {...}}

// 失败
{"code": 400, "msg": "invalid json", "data": null}

鉴权方式(除 /healthz 外必填):

Authorization: Bearer <API_KEY>
# 或
X-API-Key: <API_KEY>

GET /healthz

健康检查,无需鉴权。

响应:

{"code": 0, "msg": "ok", "data": {"health": "ok"}}

POST /upload

上传文件到服务器,返回文件 ID 供后续消息引用。

请求: multipart/form-data,字段名不限,带 filename 即可。

响应:

{
  "code": 0,
  "msg": "ok",
  "data": {
    "files": ["document.pdf", "photo.jpg"],
    "path": "document.pdf"
  }
}
  • files:所有上传文件的相对路径(文件 ID
  • path:单文件上传时的快捷字段

上传的文件超过 24 小时会被自动清理。

POST /webhook

发送 QQ 消息,支持单条和批量两种模式。

单条发送

请求:

{
  "group_id": "123456789",
  "type": "text",
  "msg": "Hello!"
}
字段 必填 说明
group_id 二选一 群号
user_id 二选一 QQ 号(私聊)
type 消息类型:text(默认)、imagefilevideo
msg text 时必填 文本内容
url image/file/video 时必填 资源链接或上传返回的文件 ID

示例:

# 发送文本
curl -X POST http://localhost:8081/webhook \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"group_id": "123456789", "type": "text", "msg": "Hello!"}'

# 发送图片URL
curl -X POST http://localhost:8081/webhook \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"group_id": "123456789", "type": "image", "url": "https://example.com/photo.jpg"}'

# 发送文件(本地已上传)
curl -X POST http://localhost:8081/webhook \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"group_id": "123456789", "type": "file", "url": "document.pdf"}'

批量发送

使用 messages 数组批量发送多条消息。textimagevideo 会组合成一条消息发送(框架自动处理冲突拆分),file 每条单独发送。

请求:

{
  "group_id": "123456789",
  "messages": [
    {"type": "text", "msg": "文件已发送"},
    {"type": "image", "url": "preview.jpg"},
    {"type": "file", "url": "document.pdf"},
    {"type": "video", "url": "demo.mp4"}
  ]
}

响应:

{
  "code": 0,
  "msg": "ok",
  "data": {
    "total": 4,
    "success": 4,
    "failed": 0,
    "results": [
      {"index": 0, "success": true},
      {"index": 1, "success": true},
      {"index": 2, "success": true},
      {"index": 3, "success": true}
    ]
  }
}

每条消息独立处理,一条失败不影响其他消息。results 数组按原始 index 排序,包含每条消息的发送结果。

命令监听

插件会自动监听 QQ 消息,当消息以 #四个中文字+空格 开头时,将命令内容 POST 到 COMMAND_CALLBACK_URL

匹配规则:

#测试命令 你好世界
│      │ │       │
│      │ │       └── 命令内容content
│      └── 空格分隔
└── 命令名4个中文字
 └── 前缀(默认 #
  • 前缀、命令名长度可通过 COMMAND_PREFIXCOMMAND_LENGTH 配置
  • 不配置 COMMAND_CALLBACK_URL 则不监听

回调请求体POST JSON

{
  "command": "测试命令",
  "content": "你好世界",
  "raw_message": "#测试命令 你好世界",
  "user_id": "123456",
  "group_id": "789012",
  "message_id": "abc123"
}
字段 说明
command 命令名4个中文字
content 命令后的内容
raw_message 原始消息文本
user_id 发送者 QQ 号
group_id 群号(私聊消息无此字段)
message_id 消息 ID

回调响应格式(自动回复到 QQ

回调服务器返回 JSON插件会自动将内容回复到原消息来源群/私聊)。

纯文本回复:

{"reply": "收到你的命令了"}

批量回复text/image/video 组合发送file 单独发送):

{
  "messages": [
    {"type": "text", "msg": "处理结果如下"},
    {"type": "image", "url": "https://example.com/result.png"},
    {"type": "file", "url": "report.pdf"}
  ]
}
字段 说明
reply 纯文本回复(与 messages 二选一,messages 优先)
messages 批量回复数组,格式同 /webhookmessages 字段
group_id 可选,覆盖回复目标群号(默认回复到原群)
user_id 可选,覆盖回复目标 QQ 号(默认回复到原发送者)

不需要回复时返回 {} 或空响应即可。

项目结构

├── plugin.py             # 插件入口,组装并启动 HTTP 服务
├── config.py             # 配置(环境变量)
├── middleware.py         # 鉴权 & 请求 ID 中间件
├── response.py           # 统一响应格式
├── handlers/
│   ├── __init__.py
│   ├── command.py        # 命令监听匹配与回调
│   ├── health.py         # GET /healthz
│   ├── message.py        # POST /webhook
│   └── upload.py         # POST /upload
├── manifest.toml         # NcatBot 插件元数据
├── .env.example          # 环境变量模板
└── pyproject.toml        # Python 依赖声明

部署建议

  • 放在 Nginx/Caddy 反向代理后,启用 HTTPS
  • 配置请求限流,防止滥用
  • 使用 systemd 管理进程:
# /etc/systemd/system/ncatbot.service
[Unit]
Description=NcatBot Webhook Plugin
After=network.target

[Service]
Type=simple
User=ncatbot
WorkingDirectory=/opt/ncatbot
EnvironmentFile=/opt/ncatbot/.env
ExecStart=/opt/ncatbot/.venv/bin/python -m ncatbot
Restart=on-failure

[Install]
WantedBy=multi-user.target

日志默认输出到 stdout可由 journald 收集查看:

journalctl -u ncatbot -f
Description
No description provided
Readme 155 KiB
Languages
Python 100%