Spaces:
Running
Running
| # 部署文档(Hugging Face Spaces) | |
| 本文档说明如何把 XTC 后端部署到 Hugging Face Spaces,采用**混合存储方案**:本地 SQLite 持久卷(热存储)+ HF Hub dataset 仓库(配置备份)。 | |
| > **存储方案说明**:本项目采用混合方案—— | |
| > - **主体数据**(令牌、会话、请求历史、用量、审计、速率限制、Webhook)存在 HF Spaces 本地的 `/data/xtc.db`(SQLite) | |
| > - **配置文件**(providers / 默认厂商)额外同步到 HF Hub dataset 仓库做备份 | |
| > | |
| > **为什么配置要走 Hub?** HF Spaces **免费档磁盘是 ephemeral(临时)**,restart/stop 会清空 `/data`,导致配置丢失。把配置 JSON 备份到 HF Hub dataset 仓库(随账号持久保存),重建后能自动拉取恢复。其余数据(会话/日志等)反正不重启也无所谓,纯本地即可。 | |
| > | |
| > **付费档用户**($5/月 Small 持久存储):`/data` 永久保留,可不配置 Hub 备份(但配了也无妨,多一层保险)。 | |
| --- | |
| ## 一、整体架构 | |
| ``` | |
| 手表端 / 前端 | |
| │ HTTPS | |
| ▼ | |
| Cloudflare Workers(反向代理,可选) | |
| │ 解决:免费域名 / 国内访问 / 48h 休眠保活 | |
| ▼ | |
| Hugging Face Spaces(Docker 类型) | |
| │ 运行 FastAPI + uvicorn | |
| ▼ | |
| /data/xtc.db(SQLite 持久卷) | |
| │ | |
| ├─ config 配置(providers / 默认厂商)──┐ 备份 | |
| ├─ access_tokens 临时令牌 │ | |
| ├─ sessions 会话历史 │ | |
| ├─ session_messages 会话消息 │ | |
| ├─ request_log 请求历史(最近 N 条) │ 仅配置 | |
| ├─ usage_log 用量统计 │ 走 Hub | |
| ├─ audit_log 审计日志 │ | |
| ├─ rate_limit 速率限制 │ | |
| └─ webhook_config Webhook 配置 │ | |
| ▼ | |
| HF Hub dataset 仓库(config/app_config.json) | |
| 解决免费档 ephemeral 问题,重建后自动恢复配置 | |
| ``` | |
| **为什么仅配置走 Hub,其余纯本地?** | |
| - 单实例部署,Hub 的"多实例同步"优势用不上,避免无谓的网络开销 | |
| - 本地 SQLite 读写比网络 API 快几个数量级 | |
| - 配置是唯一"丢了很麻烦"的数据(要重新填所有 API Key),其余数据(日志/会话)重建丢失可接受 | |
| - 图片/文件前端会重传,不需要后端长期存储 | |
| - 复杂度可控:只在 `config_store` 一处接入 Hub,其余模块无感知 | |
| **持久性保证**: | |
| - HF Spaces 免费档:restart/stop 清空 `/data`,但配置已备份到 Hub,重建后自动恢复 | |
| - HF Spaces 付费档($5/月):`/data` 永久保留,所有数据都不丢 | |
| - 删除整个 Space:`/data` 丢失,但 Hub 仓库里的配置备份仍在 | |
| --- | |
| ## 二、前置准备 | |
| ### 1. 注册 Hugging Face 账号 | |
| 访问 https://huggingface.co/join 注册(免费)。 | |
| ### 2. 准备代码仓库 | |
| 本项目代码在 GitHub 仓库 `luckfun233/AI` 的 `xtc-backend-hf/` 目录。HF Spaces 支持两种方式同步代码: | |
| - **方式 A(推荐)**:HF Space 直接从 GitHub 同步(每次 push 自动重建) | |
| - **方式 B**:手动把代码推到 HF Space 的 Git 仓库 | |
| --- | |
| ## 三、创建 HF Space | |
| ### 1. 新建 Space | |
| 1. 访问 https://huggingface.co/new-space | |
| 2. 填写: | |
| - **Space name**:`xtc-backend`(或任意名) | |
| - **License**:随意 | |
| - **SDK**:选择 **Docker** | |
| - **Space hardware**:**CPU basic (Free)**(免费档够用) | |
| - **Visibility**:**Private**(强烈建议私有,避免后台暴露) | |
| 3. 点击 **Create Space** | |
| ### 2. 绑定持久化存储(可选,付费档) | |
| **免费档磁盘是 ephemeral(临时)**,restart/stop 会清空 `/data`。本项目通过 HF Hub 仓库备份配置来规避此问题(见下一步),所以**免费档也能用**。 | |
| 如需所有数据(会话/日志等)都持久保留,可开通付费持久存储: | |
| 1. 进入刚创建的 Space | |
| 2. 点击顶部 **Settings** 标签 | |
| 3. 找到 **Persistent storage** 区域 | |
| 4. 选择容量(**20 GB Small - $5/month**,最小档够用) | |
| 5. 点击 **Attach** 并完成支付 | |
| > **免费档 vs 付费档**: | |
| > - **免费档**:配置靠 Hub 备份(不丢),其余数据 restart/stop 后清空(可接受) | |
| > - **付费档**:所有数据永久保留,Hub 备份作为额外保险 | |
| ### 3. 创建 HF Hub 配置备份仓库(免费档强烈建议) | |
| 用于备份配置文件,解决免费档磁盘 ephemeral 问题: | |
| 1. 访问 https://huggingface.co/new-dataset | |
| 2. 填写: | |
| - **Dataset name**:`xtc-config`(或任意名) | |
| - **License**:随意 | |
| - **Visibility**:**Private**(强烈建议私有,配置含 API Key) | |
| 3. 点击 **Create dataset** | |
| 记录仓库名称,格式为 `用户名/xtc-config`(如 `luckfun233/xtc-config`),后面配置 `HF_CONFIG_REPO` 要用。 | |
| ### 4. 创建 HF Access Token | |
| 用于后端读写配置备份仓库: | |
| 1. 访问 https://huggingface.co/settings/tokens | |
| 2. 点击 **New token** | |
| 3. 填写 Name(如 `xtc-backend`),Type 选 **Write**(需要写权限推送配置) | |
| 4. 复制 token(以 `hf_` 开头),后面配置 `HF_TOKEN` 要用 | |
| > **权限说明**:token 需要对上一步创建的 dataset 仓库有 write 权限。Space 和 dataset 在同一账号下时,Write token 自动有权限。 | |
| ### 5. 同步代码 | |
| **方式 A:从 GitHub 同步(推荐)** | |
| 1. Space Settings → **Repositories** → **Connect a GitHub repository** | |
| 2. 选择 `luckfun233/AI` 仓库 | |
| 3. **Root directory** 填写:`xtc-backend-hf` | |
| 4. 保存后,每次 GitHub push 自动触发 HF 重建 | |
| **方式 B:手动推送** | |
| ```bash | |
| # 在 HF 账号设置里创建 Access Token:https://huggingface.co/settings/tokens | |
| # 权限选 Write,复制 token | |
| cd xtc-backend-hf | |
| git init | |
| git remote add hf https://<你的HF用户名>:<HF_TOKEN>@huggingface.co/spaces/<你的HF用户名>/xtc-backend | |
| git add . | |
| git commit -m "init" | |
| git push hf main | |
| ``` | |
| --- | |
| ## 四、配置环境变量 | |
| **这是最关键的一步**。在 Space Settings → **Variables and secrets** 中添加以下环境变量: | |
| ### 必填(不填无法正常运行) | |
| | 变量名 | 说明 | 示例值 | | |
| |---|---|---| | |
| | `XTC_ADMIN_KEY` | 后台管理密钥,访问 `/admin` 登录用 | `my-super-admin-key-2026` | | |
| | `XTC_ACCESS_KEY` | 前端/手表端长期访问密钥 | `my-access-key-for-watch` | | |
| | `XTC_JWT_SECRET` | JWT 签名密钥(临时令牌),**必须随机长字符串** | `a1b2c3d4e5...(32位以上随机)` | | |
| > **生成随机密钥**:在本地终端运行 `openssl rand -hex 32` 生成 `XTC_JWT_SECRET`。 | |
| ### 选填(有默认值,通常不用改) | |
| | 变量名 | 默认值 | 说明 | | |
| |---|---|---| | |
| | `PORT` | `7860` | 服务端口(HF Spaces 固定 7860,不要改) | | |
| | `XTC_DB_PATH` | `/data/xtc.db` | SQLite 数据库路径(持久卷路径,不要改) | | |
| | `XTC_DISABLE_ADMIN` | `false` | 紧急关闭后台(设 `true` 则 `/admin` 不可用) | | |
| | `UPSTREAM_TIMEOUT_MS` | `120000` | 上游 API 超时(毫秒) | | |
| | `XTC_ACCESS_TOKEN_TTL_SEC` | `1800` | 临时令牌有效期(秒,60-86400) | | |
| | `XTC_ACCESS_TOKEN_LENGTH` | `8` | 临时令牌长度(6-24) | | |
| ### 选填(种子厂商,也可启动后在后台配) | |
| | 变量名 | 说明 | | |
| |---|---| | |
| | `GEMINI_API_KEY` | Gemini API 密钥(可填多个,逗号分隔) | | |
| | `OPENAI_API_KEY` | OpenAI 兼容厂商的 API 密钥 | | |
| | `OPENAI_BASE_URL` | OpenAI 兼容厂商的 base URL(默认 `https://api.openai.com`) | | |
| > **建议**:`GEMINI_API_KEY` / `OPENAI_API_KEY` 留空,启动后用 `/admin` 后台添加厂商,这样密钥存在 SQLite 而非环境变量里,方便随时增删轮询。 | |
| ### 选填(HF Hub 配置备份,免费档强烈建议) | |
| | 变量名 | 说明 | 示例值 | | |
| |---|---|---| | |
| | `HF_TOKEN` | HF Hub 访问令牌(write 权限,见第三节第 4 步) | `hf_xxxxxxxxxxxxxxxxxxxx` | | |
| | `HF_CONFIG_REPO` | 配置备份 dataset 仓库名(见第三节第 3 步) | `luckfun233/xtc-config` | | |
| > **配置后才生效**:两个变量都填了才会启用 Hub 配置备份。只填一个不生效。 | |
| > **降级行为**:未配置时,后端纯本地运行(功能正常),但 restart/stop 后配置会丢失,需重新在后台添加厂商。 | |
| > **付费档用户**:`/data` 已持久,可不配(但配了多一层保险,删 Space 重建也能恢复配置)。 | |
| ### 配置方式 | |
| 在 Space Settings → **Variables and secrets**: | |
| - **Variables**:普通环境变量(明文存储,如 `PORT`、`XTC_DB_PATH`、`HF_CONFIG_REPO`) | |
| - **Secrets**:敏感信息(加密存储,推荐用于 `XTC_ADMIN_KEY`、`XTC_ACCESS_KEY`、`XTC_JWT_SECRET`、`HF_TOKEN`、`GEMINI_API_KEY`) | |
| --- | |
| ## 五、首次启动验证 | |
| ### 1. 等待构建 | |
| Space 创建后会自动拉取代码、构建 Docker 镜像。在 Space 主页能看到构建日志,看到 `Running on http://0.0.0.0:7860` 即构建成功。 | |
| ### 2. 健康检查 | |
| 访问 `https://<你的用户名>-xtc-backend.hf.space/health`,应返回: | |
| ```json | |
| {"ok": true, "service": "xtc-backend-hf", "version": "..."} | |
| ``` | |
| ### 3. 登录后台 | |
| 访问 `https://<你的用户名>-xtc-backend.hf.space/admin`,输入 `XTC_ADMIN_KEY` 登录。 | |
| ### 4. 添加厂商 | |
| 在后台 **厂商** Tab: | |
| 1. 点击"添加厂商" | |
| 2. 填写: | |
| - **ID**:`gemini`(或任意唯一标识) | |
| - **名称**:`Gemini` | |
| - **类型**:`gemini` | |
| - **API Keys**:填入你的 Gemini API Key(每行一个,支持多密钥轮询) | |
| 3. 保存 | |
| 4. 设为默认厂商 | |
| ### 5. 测试对话 | |
| 在后台 **测试** Tab,输入消息测试是否正常返回。 | |
| ### 6. 测试 API | |
| ```bash | |
| curl -X POST https://<你的用户名>-xtc-backend.hf.space/v1/chat/completions \ | |
| -H "Authorization: Bearer <XTC_ACCESS_KEY>" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "model": "gemini-flash-latest", | |
| "messages": [{"role": "user", "content": "你好"}] | |
| }' | |
| ``` | |
| --- | |
| ## 六、Cloudflare Workers 反向代理(可选但推荐) | |
| 解决三个问题: | |
| 1. **免费域名**:HF Spaces 默认域名 `*.hf.space` 在国内可能无法访问 | |
| 2. **国内访问**:CF Workers 节点在国内可达 | |
| 3. **48h 休眠保活**:HF 免费档 48h 无请求会休眠,CF Workers 定时器保活 | |
| ### 1. 创建 Worker | |
| 在 Cloudflare Dashboard → Workers & Pages → Create Worker: | |
| ```javascript | |
| export default { | |
| async fetch(request) { | |
| const url = new URL(request.url); | |
| url.hostname = '<你的用户名>-xtc-backend.hf.space'; | |
| return fetch(url, request); | |
| }, | |
| // 每 24 小时保活一次 | |
| async scheduled(event, env, ctx) { | |
| ctx.waitUntil(fetch('https://<你的用户名>-xtc-backend.hf.space/health')); | |
| } | |
| }; | |
| ``` | |
| ### 2. 配置定时器 | |
| Worker Settings → **Triggers** → **Cron Triggers**: | |
| ``` | |
| 0 */12 * * * | |
| ``` | |
| (每 12 小时触发一次,保活) | |
| ### 3. 绑定自定义域名(可选) | |
| Worker → Settings → **Triggers** → **Custom Domains**,添加你自己的域名。 | |
| --- | |
| ## 七、数据备份与恢复 | |
| ### 自动备份(配置文件) | |
| 配置了 `HF_TOKEN` + `HF_CONFIG_REPO` 后,每次在后台修改厂商配置都会**自动**把配置 JSON 推送到 HF Hub dataset 仓库的 `config/app_config.json`。无需手动操作。 | |
| ### 手动备份 | |
| 后台 → **概览** Tab 有"导出配置"按钮,可下载 `app_config.json`(含所有厂商配置)到本地。 | |
| 如需备份完整数据库(含会话/日志),需通过 SSH/终端方式(HF Spaces 付费档支持)复制 `/data/xtc.db`。 | |
| ### 恢复 | |
| - **免费档 restart/stop 后**:`/data` 被清空,但启动时后端会自动从 Hub 拉取 `config/app_config.json` 恢复配置(需已配置 `HF_TOKEN` + `HF_CONFIG_REPO`)。其余数据(会话/日志)丢失。 | |
| - **付费档重建后**:`/data` 保留,所有数据自动恢复,无需操作。 | |
| - **删除 Space 重建**:先配置环境变量(含 `HF_TOKEN` + `HF_CONFIG_REPO`),启动后配置自动从 Hub 恢复;或登录后台 → 厂商 → 导入手动导出的配置 JSON。 | |
| --- | |
| ## 八、常见问题 | |
| ### Q1: 重建 Space 后配置丢失? | |
| **原因**:免费档磁盘是 ephemeral,restart/stop 会清空 `/data`;且未配置 HF Hub 配置备份。 | |
| **解决**: | |
| 1. 配置 `HF_TOKEN` + `HF_CONFIG_REPO` 环境变量(见第三节第 3-4 步),启用配置自动备份 | |
| 2. 启动时后端会自动从 Hub 拉取配置恢复 | |
| 3. 或开通付费持久存储($5/月),`/data` 永久保留 | |
| ### Q2: 后台登录提示 "invalid admin key"? | |
| **原因**:`XTC_ADMIN_KEY` 环境变量未设置或拼写错误。 | |
| **解决**:Space Settings → Variables and secrets 检查 `XTC_ADMIN_KEY`,注意 Secrets 修改后需要重启 Space。 | |
| ### Q3: 手表端请求返回 401? | |
| **原因**:`XTC_ACCESS_KEY` 不匹配,或请求头格式错误。 | |
| **解决**: | |
| - 请求头格式:`Authorization: Bearer <XTC_ACCESS_KEY>` | |
| - 检查环境变量值是否前后有空格 | |
| ### Q4: Space 休眠了怎么办? | |
| **原因**:HF 免费档 48h 无请求自动休眠。 | |
| **解决**: | |
| - 配置 Cloudflare Workers 定时器(见第六节) | |
| - 或用外部监控服务(如 UptimeRobot)每 5 分钟 ping `/health` | |
| ### Q5: 怎么查看请求日志? | |
| 后台 → **请求历史** Tab,默认保留最近 500 条完整请求(含标头、body、响应、耗时、错误码)。可在该 Tab 调整保留条数(0-2000)。 | |
| ### Q6: 怎么添加多个 API Key 做轮询? | |
| 后台 → **厂商** → 编辑厂商 → **API Keys** 字段,每行填一个 key,自动轮询。 | |
| ### Q7: 国内访问慢/连不上? | |
| 1. 用 Cloudflare Workers 反向代理(见第六节) | |
| 2. 或绑定自定义域名走 CF CDN | |
| --- | |
| ## 九、环境变量完整清单 | |
| ```bash | |
| # ===== 必填 ===== | |
| XTC_ADMIN_KEY=<你的后台管理密钥> | |
| XTC_ACCESS_KEY=<前端访问密钥> | |
| XTC_JWT_SECRET=<32位以上随机字符串> | |
| # ===== 默认值(通常不用改)===== | |
| PORT=7860 | |
| XTC_DB_PATH=/data/xtc.db | |
| XTC_DISABLE_ADMIN=false | |
| UPSTREAM_TIMEOUT_MS=120000 | |
| XTC_ACCESS_TOKEN_TTL_SEC=1800 | |
| XTC_ACCESS_TOKEN_LENGTH=8 | |
| # ===== 种子厂商(可选,留空用后台配)===== | |
| GEMINI_API_KEY= | |
| OPENAI_API_KEY= | |
| OPENAI_BASE_URL=https://api.openai.com | |
| # ===== HF Hub 配置备份(免费档强烈建议)===== | |
| HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxx | |
| HF_CONFIG_REPO=你的用户名/xtc-config | |
| ``` | |
| --- | |
| ## 十、文件结构说明 | |
| 部署后 Space 内的关键文件: | |
| ``` | |
| /data/ # 本地存储卷(免费档 ephemeral,付费档持久) | |
| └── xtc.db # SQLite 数据库(所有数据,配置额外备份到 Hub) | |
| /app/ # 应用代码(每次重建从 Git 拉取) | |
| ├── Dockerfile | |
| ├── requirements.txt | |
| └── app/ | |
| ├── main.py # FastAPI 入口 | |
| ├── config.py # 环境变量配置 | |
| ├── database.py # SQLite 初始化 | |
| ├── hf_storage.py # HF Hub 配置备份抽象层 | |
| ├── auth.py # 鉴权(admin key + access key + JWT) | |
| ├── middleware.py # 速率限制中间件 | |
| ├── request_log_middleware.py # 请求日志中间件 | |
| ├── errors.py # 统一错误模型 | |
| ├── admin_html.py # 后台 HTML | |
| ├── adapters/ # Gemini/OpenAI 适配器 | |
| ├── services/ # 业务逻辑层(config_store 接入 Hub 备份) | |
| └── api/ # API 路由 | |
| ``` | |