xtc-backend / DEPLOY.md
a3216's picture
deploy: initial release to Hugging Face Spaces
36fae79
|
Raw
History Blame Contribute Delete
15.6 kB

部署文档(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/AIxtc-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 namextc-backend(或任意名)
    • License:随意
    • SDK:选择 Docker
    • Space hardware:**CPU basic (Free)**(免费档够用)
    • VisibilityPrivate(强烈建议私有,避免后台暴露)
  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 namextc-config(或任意名)
    • License:随意
    • VisibilityPrivate(强烈建议私有,配置含 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 → RepositoriesConnect a GitHub repository
  2. 选择 luckfun233/AI 仓库
  3. Root directory 填写:xtc-backend-hf
  4. 保存后,每次 GitHub push 自动触发 HF 重建

方式 B:手动推送

# 在 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:普通环境变量(明文存储,如 PORTXTC_DB_PATHHF_CONFIG_REPO
  • Secrets:敏感信息(加密存储,推荐用于 XTC_ADMIN_KEYXTC_ACCESS_KEYXTC_JWT_SECRETHF_TOKENGEMINI_API_KEY

五、首次启动验证

1. 等待构建

Space 创建后会自动拉取代码、构建 Docker 镜像。在 Space 主页能看到构建日志,看到 Running on http://0.0.0.0:7860 即构建成功。

2. 健康检查

访问 https://<你的用户名>-xtc-backend.hf.space/health,应返回:

{"ok": true, "service": "xtc-backend-hf", "version": "..."}

3. 登录后台

访问 https://<你的用户名>-xtc-backend.hf.space/admin,输入 XTC_ADMIN_KEY 登录。

4. 添加厂商

在后台 厂商 Tab:

  1. 点击"添加厂商"
  2. 填写:
    • IDgemini(或任意唯一标识)
    • 名称Gemini
    • 类型gemini
    • API Keys:填入你的 Gemini API Key(每行一个,支持多密钥轮询)
  3. 保存
  4. 设为默认厂商

5. 测试对话

在后台 测试 Tab,输入消息测试是否正常返回。

6. 测试 API

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:

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 → TriggersCron Triggers

0 */12 * * *

(每 12 小时触发一次,保活)

3. 绑定自定义域名(可选)

Worker → Settings → TriggersCustom 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

九、环境变量完整清单

# ===== 必填 =====
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 路由