sansenhoshiandClaude Code ed75a66982 feat(core): 出站媒体内联化全局钩子 / 本地文件改写为协议端可达 URL
协议端不在本机,而 NoneBot 的 f2s() 会把 Path 转成 file:///D:/...(file:// 的
语义是「协议端那台机器上的路径」),必然 ENOENT。受影响的不止本仓调用点,还有
装不了改不动的 pip 社区插件(本次报错来自 nonebot_plugin_doroending),只能全局拦截。

- 新增 hexi/core/outbound_media.py:挂 Bot.on_calling_api(公开钩子、适配器不覆盖),
  在真正调用适配器前原地改写发送类 API 的 data:默认改写成
  http://<本机可达IP>:<端口>/media/<token> 由协议端主动回拉(地址与 /hub 首页
  「协议端配对」同源,零新配置),拿不到可达地址时回退 base64://
- 文件上传类(upload_group_file / upload_private_file)单独处理:file 在顶层且
  只做 URL 不做 base64(几十上百 MB 不适合内联),覆盖 video_analysis 群文件
  「本地直传」兜底与 alconna 的 $onebot11:file
- 媒体路由 get_app().mount("/media", sub) 复用现有端口不新开服务;免鉴权是必须的
  (协议端登录不了 hub),安全模型改为「路径由 bot 改写那一刻自己登记、请求方只能
  出示不可猜 token」,配短 TTL;_mounted 为 False 时绝不发 URL
- 钩子内每个段独立 try/except,任何异常只告警不抛,绝不反过来把发送搞挂
- message_utils.common_proc_reply 占位图不再自己转 base64,改传 path= 交给钩子,
  避免两处各有一套策略
- tests/test_outbound_media.py:用 tmp_path 造真实文件而非 mock 文件系统,重点覆盖
  file:// 解析(空格/中文编码、手工未转义的字面 %XX)与 walker 各消息形态

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:47:09 +08:00
2026-09-08 14:25:32 +08:00
2026-09-08 14:25:32 +08:00
2026-09-08 14:25:32 +08:00

禾汐 (HeXi)

基于 NoneBot2 的个人娱乐 QQ 机器人,使用 OneBot V11 协议接入。集成了游戏战绩查询、群聊学习、每日打卡、人设卡、表情包等大量功能,以插件化方式组织,方便增删。

功能特性

游戏相关

插件 功能 主要命令
nonebot_plugin_bf_bot 战地系列 (BF3/BF4/BF1/BFV/BF2042/BF6) 战绩查询,PIL 生成统计卡片 /bft /bfbind /unbind /update_bind
nonebot_plugin_deadlock Deadlock 战绩、段位、近期比赛查询 /nekoscore /nekobind /nekounbind /nekorank /nekomatch
nonebot_plugin_steam_info Steam 玩家信息、库存、游戏时长查询 /steamhelp /steambind /steaminfo /steamplaytime 等
nonebot_plugin_helldivers_tools 绝地潜兵 2 前线战况简报、星球详报、随机战备推荐 /简报 /详报 /随机战备
nonebot_plugin_mc_server_status Minecraft 服务器状态查询 /信息 /信息数据
nonebot_plugin_ncm_saying 网易云音乐热评(网抑云) /网抑云
nonebot-bison Bilibili / 微博等订阅推送 —

聊天娱乐

插件 功能 主要命令
nonebot_plugin_learning_chat 马尔可夫链群聊学习:被动学习群消息并模仿回复,定时主动发言;附 Vue 3 Web 管理后台 —
nonebot_plugin_galgame_card 群友"人设卡"生成与展示,带 Web 管理后台 —
nonebot_plugin_group_tools 群工具集(头像、表情、签到素材、游戏素材图等) —
nonebot_plugin_dailywife 每日随机抽取群友当"老婆" /今日老婆
nonebot_plugin_deer_pipe 每日打卡(鹿)与打卡记录,日历可视化 /打卡记鹿 /查询记录
nonebot_plugin_makeaquote 生成"名言"引用图片 —
memes_ops 表情包运营/管理 —
nonebot_plugin_random_jm_code 随机 JM 本子代码 /jm
nonebot_plugin_dice 骰子掷点 —

实用工具

插件 功能 主要命令
hexi/core(核心模块) 核心库:消息解析、权限分级、限流器 (token bucket)、命令冷却、热插件管理(非插件) —
nonebot_plugin_video_analysis 视频链接解析 —
nonebot_plugin_regif GIF 注册与处理 —
nonebot_plugin_picfinder_take 识图(Playwright 驱动) —
nonebot_plugin_picstatus 头像状态图生成 —
nonebot_plugin_group_daily_analysis 群聊行为分析报告 /群分析
hexi/web_hub(核心模块) 统一 Web 管理入口 /hub(非插件) —

快速开始

环境要求

  • Python 3.10+,使用 Poetry 管理依赖
  • 一个 OneBot V11 实现(如 NapCat、Lagrange)作为 QQ 接入端

安装与启动

# 安装依赖
poetry install

# 配置环境变量(见下节),然后启动
poetry run python bot.py
  • 开发:使用 .env.dev(监听 127.0.0.1:11011,昵称 Elika)
  • 生产:复制为根目录 .env 后启动(监听 0.0.0.0:39697,超级用户 2931589710,昵称 爱丽丝)

.env / .env.dev 均已被 .gitignore 排除,包含凭据的文件不会进入仓库。

配置

启动时 NoneBot 自动加载根目录 .env 文件,主要变量:

变量 说明
HOST / PORT 监听地址与端口
SUPERUSERS 超级用户 QQ 号
NICKNAME 机器人昵称
COMMAND_START / COMMAND_SEP 命令前缀与分隔符
DRIVER NoneBot 驱动器(httpx + fastapi + websockets)
ONEBOT_ACCESS_TOKEN OneBot 接入鉴权 token
DATASTORE_* 数据目录(localstore 统一指向 hexi/data/ 等)
SENTRY_DSN / SENTRY_ENVIRONMENT Sentry 错误上报(可选)
BISON_* Bison 订阅推送配置

各插件专属配置(Steam API key、网易云 cookie、识图等)按需在 .env 中补充,详见各插件文档。

目录结构

HeXi/
├── bot.py  pyproject.toml  README.md
├── hexi/
│   ├── plugins/      # 全部插件(pyproject [tool.nonebot] plugin_dirs 加载)
│   ├── core/         # 机器人核心模块(非插件):工具库/插件控制面/热拔插管理
│   ├── web_hub/      # 机器人核心模块:统一 Web 管理台 + 鉴权/插件注册/配置标准
│   ├── data/         # 运行数据(不入库)
│   ├── config/       # 业务配置(不入库)
│   ├── resource/     # 全局静态资源(fonts/ 字体、menu_config 等)
│   ├── web/          # 统一 Web 前端(React + Vite,构建产物 dist/ 供 /hub 挂载)
│   ├── logs/         # 日志(不入库)
│   └── web_hub/      # 见上:统一 Web 管理台/鉴权/插件注册/配置标准
├── docs/             # 插件开发标准文档
├── tests/            # pytest 测试
└── plugin_template/  # 新插件脚手架模板
  • 数据库:hexi/data/data.db(datastore)、hexi/data/nonebot_plugin_orm/db.sqlite3(orm,各插件表)
  • 群聊学习数据:hexi/data/record.json + inverted_index.json(马尔可夫链)
  • 本地插件数据通过 localstore 统一收进 hexi/data/,避免散落根目录

测试与开发

poetry run pytest          # 运行测试(tests/,asyncio auto 模式)
poetry run black .         # 格式化
poetry run isort .         # import 排序
poetry run ruff check .    # lint
poetry run pyright         # 类型检查

注意:测试文件必须放在 tests/,不要放进 test/ —— pyproject.toml 中 test 是插件目录,NoneBot 启动时会把其中所有文件当插件加载。

新增插件请参考:

许可

无

S
Description
No description provided
Readme
653 MiB
Languages
Python 66.4%
HTML 26.7%
TypeScript 6.1%
CSS 0.5%
Jinja 0.2%