{"id":51152552,"url":"https://github.com/zzttzzmyswy/astrbot_plugin_botapi","last_synced_at":"2026-06-26T07:03:11.136Z","repository":{"id":367460787,"uuid":"1279248244","full_name":"zzttzzmyswy/astrbot_plugin_botapi","owner":"zzttzzmyswy","description":"BotAPI 自定义移动端适配器 — AstrBot 插件（REST+SSE，弱网断连恢复）","archived":false,"fork":false,"pushed_at":"2026-06-26T04:11:35.000Z","size":138,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T06:09:19.658Z","etag":null,"topics":["astrbot","astrbot-plugin","bot-api","llm-chatbot","mobile","sse"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zzttzzmyswy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-24T14:04:17.000Z","updated_at":"2026-06-26T04:11:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zzttzzmyswy/astrbot_plugin_botapi","commit_stats":null,"previous_names":["zzttzzmyswy/astrbot_plugin_botapi"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/zzttzzmyswy/astrbot_plugin_botapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zzttzzmyswy%2Fastrbot_plugin_botapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zzttzzmyswy%2Fastrbot_plugin_botapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zzttzzmyswy%2Fastrbot_plugin_botapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zzttzzmyswy%2Fastrbot_plugin_botapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zzttzzmyswy","download_url":"https://codeload.github.com/zzttzzmyswy/astrbot_plugin_botapi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zzttzzmyswy%2Fastrbot_plugin_botapi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34806448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astrbot","astrbot-plugin","bot-api","llm-chatbot","mobile","sse"],"created_at":"2026-06-26T07:03:10.365Z","updated_at":"2026-06-26T07:03:11.119Z","avatar_url":"https://github.com/zzttzzmyswy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BotAPI 移动端适配器（AstrBot 插件）\n\n\u003e 为 AstrBot 提供一个**自定义移动端 HTTP API**：手机 App 通过 REST 发消息、SSE 长连接收回复，专为弱网/后台断连设计——**断连不丢会话上下文，重连自动补消息**。一人一 Bot 的极简移动端接入方案。\n\u003e\n\u003e 适用 AstrBot ≥ 4.25.5。\n\n## 它解决什么\n\n| 痛点 | webchat | BotAPI |\n|:--|:--|:--|\n| 手机切后台断连 | WebSocket 被 OS 杀，session 结束 | SSE 自动重连 + session 绑定 token（不依赖连接） |\n| 重连后历史 | 新 session 全丢 | `GET /history?since=\u003cid\u003e` 补全漏掉的消息 |\n| 弱网 | TCP 超时触发清理 | REST 消息是离散请求，发完即成功 |\n| 流式回复 | 需 WS 双向 | SSE 单向长连，原生支持逐 token 流式 |\n\n## 架构\n\n```\n手机 App ──REST+SSE──► BotAPI 适配器插件（AstrBot）\n                         │\n                         ├─ BotApiAdapter(Platform)  跑 HTTP 服务(端口可配) + SSE 回流\n                         │   └─ BotApiMessageEvent 重写 send/send_streaming 推 SSE\n                         ├─ BotApiStar(Star)        持 context，注册管理 API + 注入 managers\n                         └─ RuntimeState 单例       跨 Platform↔Star 共享状态\n                                   │\n                                   ▼\n                         AstrBot ConversationManager（SQLite，唯一历史真相源）\n```\n\n关键设计：\n- **Session 与连接解耦**：token 绑定 session，不依赖 SSE 连接状态。断连重连同 token 即续上。\n- **纯 SSE 回复**：`POST /message` 只返回 `message_id`，所有回复（含首条）经 `/stream` SSE 推送。\n- **逐 token 流式**：入站时 `set_extra(\"enable_streaming\", True)`，`send_streaming` 逐片段推 `thinking` / `message(streaming)` / `message(final)`。\n- **断连补消息**：每条文本消息镜像写入 `platform_message_history` 表（稳定自增 int id），重连 `?since=\u003cid\u003e` 补拉。\n- **文本持久化、媒体不入库**：服务端只持久化文本（含 thinking/工具状态）；图片/音频/文件仅 SSE 推送一次（单次有效 URL），App 本地缓存。\n\n## 安装\n\n### 方式一：zip 安装\n\n1. 下载 [release zip](https://github.com/zzttzzmyswy/astrbot_plugin_botapi/releases)，解压到 AstrBot 的 `data/plugins/`：\n   ```bash\n   unzip astrbot_plugin_botapi.zip -d /path/to/AstrBot/data/plugins/\n   # 生成 data/plugins/astrbot_plugin_botapi/（含 main.py + metadata.yaml + pages/）\n   ```\n2. 重启 AstrBot。日志应见 `Platform adapter registered: botapi`。\n3. WebUI → **插件管理** → 确认 `astrbot_plugin_botapi` 已加载。\n4. WebUI → **机器人/平台** → 新增 → 选 type `botapi` → 填配置 → **启用**（`enable` 默认 false，须手动启用）。\n\n### 方式二：git clone\n\n```bash\ncd /path/to/AstrBot/data/plugins/\ngit clone https://github.com/zzttzzmyswy/astrbot_plugin_botapi.git\n```\n然后同上重启 + 启用。\n\n## 配置\n\nWebUI「机器人/平台」编辑 botapi 实例：\n\n| 字段 | 默认 | 说明 |\n|:--|:--|:--|\n| `host` | `0.0.0.0` | 监听地址 |\n| `port` | `9000` | 手机 API 端口（nginx 反代） |\n| `tokens` | `[]` | 允许的 Token 列表（**空则允许所有非空 token**）；每个 token = 一个账户，自动隔离会话 |\n| `nicknames` | `{}` | `{token: 昵称}`，仅管理页展示用，不注入对话 |\n| `enable` | `false` | **须手动启用** |\n\n另需在 AstrBot 全局配置设 **`callback_api_base`**（仪表盘外部可达地址，如 `http://your-host:6185`）——媒体 URL 依赖它；不配则媒体功能降级（文本不受影响）。\n\n\u003e **多账户**：一个 botapi 实例 + `tokens` 填多个即可，一个端口服务所有账户，每个 token 自动隔离会话/历史/SSE。不要建多个 botapi 实例（每个是独立 Quart，不能共享端口）。\n\n## 手机端接口\n\n完整接口文档见 **[docs/API.md](docs/API.md)**。速览：\n\n| 端点 | 方法 | 说明 |\n|:--|:--|:--|\n| `/api/v1/botapi/auth` | POST | Token 认证 → `{user_id, session_id}` |\n| `/api/v1/botapi/message` | POST | 发消息 → `{message_id}`（纯 SSE，回复走 /stream） |\n| `/api/v1/botapi/upload` | POST multipart | 上传文件 → `{file_id, name, mime_type, size}` |\n| `/api/v1/botapi/stream?since=` | GET | SSE 流，事件类型 `message` / `thinking` / `error` / `ping` |\n| `/api/v1/botapi/history` | GET | 拉历史 / 断连补消息 |\n\n## 管理页\n\nWebUI → 插件管理 → `astrbot_plugin_botapi` → **Dashboard**：\n- 账户列表（昵称 / Token 预览 / hash / 在线 / 消息数 / SSE 连接数 / 最后活跃）\n- 新增账户（可填昵称 + 自动生成 token）\n- 导出对话记录（Markdown / JSON，完整历史无条数上限，Blob 下载）\n- 改名 / 删除 / 强制断开 / 清空历史\n- 统计卡片（总账户 / 在线 / 总消息数）\n\n## Nginx 反代（SSE 必须）\n\n```nginx\n# BotAPI 手机 API + SSE\nlocation /api/v1/botapi/ {\n    proxy_pass http://127.0.0.1:9000;\n    proxy_http_version 1.1;\n    proxy_buffering off;          # SSE 必须关缓冲\n    proxy_cache off;\n    proxy_read_timeout 86400s;    # 24h 不超时\n    proxy_send_timeout 86400s;\n    chunked_transfer_encoding on;\n}\n# 媒体 URL（走仪表盘文件服务 /api/file/\u003ctoken\u003e，免认证但单次有效）\nlocation /api/file/ { proxy_pass http://127.0.0.1:6185; }\n# 仪表盘 + 管理 API\nlocation / { proxy_pass http://127.0.0.1:6185; }\n```\n对公只开 443，9000/6185 仅本地监听。\n\n## 自检\n\n仓库 `scripts/selfcheck.sh`：\n```bash\n./scripts/selfcheck.sh --base http://localhost:9000 --token YOUR_TOKEN\n./scripts/selfcheck.sh --base https://your.domain --token YOUR_TOKEN --msg \"你好\"   # 含收发(需 LLM)\n```\n\n## 已知限制（设计取舍）\n\n- **工具事件**：结构化 `tool_call`/`tool_result` 对非 webchat 平台不可达，降级为 `message` + `subtype:\"tool_status\"` 文本（受 `show_tool_use` 控制）。\n- **媒体 URL**：走仪表盘 `/api/file/\u003ctoken\u003e`，**单次有效 + 默认 300s 过期**，App 须收到即下载缓存；服务端不持久化媒体，历史不回放媒体。\n- **流式依赖 provider**：BotAPI per-request 强制流式（`set_extra(\"enable_streaming\", True)`），但 provider 端需支持 streaming_response。\n- **历史分页**：`/history` 基于 `platform_message_history` 表（最多取最近 200 条），`since` 早于窗口时仅返回窗口内。\n\n## 更新日志\n\n见 [CHANGELOG.md](CHANGELOG.md)。\n\n## 开发\n\n```bash\ngit clone https://github.com/zzttzzmyswy/astrbot_plugin_botapi.git\ncd astrbot_plugin_botapi\npython -m venv .venv --system-site-packages   # 继承系统 astrbot 依赖\n.venv/bin/pip install pytest-asyncio\n.venv/bin/python -m pytest -q                  # 75 个测试\n```\n\n## License\n\n[MIT](LICENSE)。\n\n\u003e 注：AstrBot 本体为 AGPL-3.0。本插件按 MIT 发布；如需与 AstrBot 的 copyleft 完全一致，可改用 AGPL-3.0（替换 LICENSE 即可）。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzzttzzmyswy%2Fastrbot_plugin_botapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzzttzzmyswy%2Fastrbot_plugin_botapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzzttzzmyswy%2Fastrbot_plugin_botapi/lists"}