visual-journal / docs /deployment /huggingface-space-free.md
Visual Journal deploy
Deploy 8e0aeb3 to Docker Space
84810e9
|
Raw
History Blame Contribute Delete
17.6 kB
# Hugging Face Space 部署
本文档描述如何把本项目部署到 Hugging Face Docker Space,用作公网图片生成服务。Docker Space 的创建和更新权限取决于 Hugging Face 的当前账户政策;固定目标已存在且元数据标识为 Docker,部署脚本会直接使用认证 Git 推送,避免 `hf upload` 触发创建接口的已知 `402`。这不绕过新建 Docker Space 的账户限制。
## 目标形态
- 手机浏览器可以访问 Space 网页并正常生图。
- 电脑上的 Agent 可以通过 `/api/agent/*` 调用同一个 Space 生图。
- 首战场景是中文内容运营者为小红书笔记、商品详情页或活动海报生成首版视觉稿,不是公开 SaaS。
- 状态后端使用 `memory`,不依赖 SQLite、PostgreSQL 或外部数据库。
- 图片 Web 结果优先保存在浏览器 IndexedDB,减少服务端临时盘依赖。
## Space README YAML
本仓库顶层 `README.md` 已包含 Hugging Face Space metadata。如果你维护的是单独的 Space 仓库,确认它的 `README.md` 顶部使用 Docker SDK,并暴露本项目端口:
```yaml
---
sdk: docker
app_port: 4783
---
```
官方依据:
- Docker Space 配置、Variables/Secrets 和权限说明:https://huggingface.co/docs/hub/main/spaces-sdks-docker
- Space 硬件与计费政策:https://huggingface.co/docs/hub/main/spaces-gpus
- Hugging Face CLI 安装和登录说明:https://huggingface.co/docs/huggingface_hub/en/guides/cli
## 全新电脑前置条件
全新用户、全新电脑需要先准备系统级工具。没有 Node.js 和 npm 时,仓库内 npm 脚本无法运行;没有 HF CLI 登录时,脚本无法把 Secret 写到远端 Space。
先检查:
```bash
node --version
npm --version
hf --help
hf auth whoami
```
要求:
- Node.js >=22.15.0。
- npm 随 Node.js 一起可用。
- Hugging Face CLI 使用当前官方 `hf` 命令。
- `hf auth login` 使用 Hugging Face Access Token,不是账号密码。
- Docker 只对本地 Space-like 容器 smoke(推荐 `npm run smoke:hf-space-local`,兼容别名 `npm run smoke:hf-space`)和本地容器验证必需;远端部署由 `npm run deploy:space` 统一执行。
安装 Hugging Face CLI 时,以官方文档为准。不要把远程安装脚本直接管道到 shell;如需使用官方脚本,先下载、核对来源和内容后再执行。
第一次拉取仓库后安装依赖:
```bash
npm run install-scripts:check
npm run npm-install-policy:check
npm ci --strict-allow-scripts
npm run dependencies:check
```
项目支持 Node.js >=22.15.0;本地先校验锁文件中的安装脚本白名单,并确认 npm 支持 `--strict-allow-scripts`,完成确定性安装后核对直接依赖。旧 npm 会被安装门禁明确拒绝,升级 npm 后再重试。GitHub Actions 和 Docker 使用 Node 26,并额外启用 npm 的 `--strict-allow-scripts`。
如果不确定当前机器缺什么,运行只读诊断:
```bash
npm run doctor
```
`doctor` 会检查 Node、npm、`hf` CLI、HF 登录状态、`node_modules`、git、Docker、固定 Space 目标、远端 Variables 和远端 Secrets。该命令不会写远端 Secret、不会重启 Space、不会打印 Secret 值。
## 管理员命令中心
本仓库只保留一组稳定管理员入口:
```bash
npm run status
npm run doctor
npm run verify
npm run deploy:local
npm run deploy:space
npm run agent:doctor
```
- `status`:只读输出 git、Node、固定 Space 目标、Agent capabilities 路径和 Skill 入口。
- `doctor`:统一诊断入口,默认包含 HF Space 只读远端检查,并校验当前 npm 是否支持严格安装脚本策略、本地 `node_modules` 隐藏锁文件和直接依赖版本是否与根锁文件一致。
- `verify`:提交前基线,先核对锁文件安装脚本与 `allowScripts` 白名单、当前 npm 严格安装策略能力和已安装直接依赖,再执行测试、lint、脚本语法、构建和 `git diff --check`;需要真实 PostgreSQL gate 时加 `--postgres`。
- `deploy:local`:拒绝脏工作区后重建本地 Docker 服务,等待 healthcheck、核验镜像 revision 并探测真实 HTTP 端点;加 `--memory` 会断言 memory/indexeddb overlay 生效,加 `--postgres` 会断言 postgres/fs overlay 生效且要求通过 shell 或 Compose `.env` 提供 `GPT_IMAGE_POSTGRES_PASSWORD`。默认 Compose 只绑定 `127.0.0.1:4783`;需要非回环发布时必须显式设置 `GIP_BIND_HOST` 和 `APP_PASSWORD`。
- `deploy:space`:上传当前干净 git HEAD 到固定 HF Space,并做只读公网验证;已存在 Docker Space 根据远端元数据直接使用认证 Git 推送,其他类型才优先尝试 `hf upload`。
- `agent:doctor`:通过仓库 Skill 脚本执行只读 Agent API 契约检查,不触发真实生图。
HF Space 交互使用官方 `hf` CLI。不要维护本机 access 文件,不要把 `APP_PASSWORD`、`AGENT_API_TOKEN`、OpenAI Key 或 Hugging Face token 写入仓库文件。
部署当前干净的 git HEAD 到固定 Space:
```bash
npm run deploy:space
```
该脚本会:
- 使用 `git status --porcelain` 拒绝脏工作区。
- 使用 `git archive HEAD` 生成临时源码目录,只上传已跟踪源码。
- Space 发布包会排除根目录 `readme-images/` 中的 README 文档截图,以兼容 Hugging Face Git 的二进制文件门禁;Space README 会改用对应 GitHub 提交的不可变图片地址。
- 读取远端 Space 元数据;当前固定 Docker Space 直接克隆、同步已跟踪源码并使用认证 Git 推送。
- 非 Docker Space 才优先使用 `hf upload`;仅当它命中既有 Docker Space 创建政策 `402` 时才回退到认证 Git 推送,其他错误不会自动回退。
- 等待新 Space commit 进入 `RUNNING`。
- 检查 `/api/auth-status`、`/api/agent/capabilities` 和 `/api/runtime-capabilities`,不触发真实生图。
配置或轮换 Variables/Secrets 时,直接使用官方 `hf` CLI:
```bash
hf spaces variables add misonL/visual-journal -e AGENT_STATE_BACKEND=memory
hf spaces variables add misonL/visual-journal -e NEXT_PUBLIC_IMAGE_STORAGE_MODE=indexeddb
hf spaces variables add misonL/visual-journal -e APP_LOG_LEVEL=warn
hf spaces secrets add misonL/visual-journal -s APP_PASSWORD=<page-access-code>
hf spaces secrets add misonL/visual-journal -s AGENT_API_TOKEN=<long-random-agent-token>
```
源码部署、远端诊断、Variables 和 Secrets 都由仓库命令与 `hf` CLI 协同完成;部署回退只使用现有 Git 凭据,不维护第二套 access-file 或 Secret 同步流程。
## Space Variables
在 Space Settings 中添加这些 Variables:
```dotenv
AGENT_STATE_BACKEND=memory
NEXT_PUBLIC_IMAGE_STORAGE_MODE=indexeddb
APP_LOG_LEVEL=warn
```
`NEXT_PUBLIC_IMAGE_STORAGE_MODE` 是构建期和运行期都需要的值。Dockerfile 已声明 build arg,Hugging Face Docker Space 会把同名 Variable 作为 build arg 传入构建,并在运行期注入环境变量。
如果不使用 `memory`,再按实际状态后端追加可选变量:
```dotenv
AGENT_SQLITE_PATH=generated-images/.agent-state/agent.sqlite
AGENT_DATABASE_URL=postgres://...
AGENT_DB_PASSWORD=<database-password>
AGENT_DB_PASSWORD_FILE=/path/to/password-file
```
`AGENT_DATABASE_URL`、`AGENT_DB_PASSWORD` 和 `AGENT_DB_PASSWORD_FILE` 是 PostgreSQL 配置路径,不需要在 `memory` 模式下设置为空值。
可选:
```dotenv
AGENT_PUBLIC_BASE_URL=https://<user>-<space>.hf.space
```
`AGENT_PUBLIC_BASE_URL` 影响 OpenAPI `servers[0].url`,也用于 `POST /api/agent/artifacts/{id}/share` 返回用户可打开的分享外链。必须填写绝对 `http`/`https` URL,不能包含凭据、查询参数或片段;Agent skill 仍应以 `GPT_IMAGE_PLAYGROUND_URL` 指向实际 Space 地址。
## Space Secrets
在 Space Settings 中添加 Secrets,不要写入仓库文件:
```dotenv
OPENAI_API_KEY=<your-api-key>
OPENAI_API_BASE_URL=https://api.openai.com/v1
# 可选:仅服务端到上游的无认证 HTTP(S) 代理。
OPENAI_UPSTREAM_PROXY_URL=http://proxy.internal:8080
APP_PASSWORD=<page-access-code>
AGENT_API_TOKEN=<long-random-agent-token>
```
`OPENAI_API_BASE_URL` 和 `OPENAI_CHANNEL_N_BASE_URL` 必须是无凭据、无查询参数和无片段的 `http` 或 `https` 绝对地址,通常以 `/v1` 结尾。公网 Space 推荐使用 `https` 上游;只有内网、专用代理或已确认的兼容渠道需要 `http` 时才配置 `http`。
`OPENAI_UPSTREAM_PROXY_URL` 只影响 Space 服务端到上游 API 的出站连接,不影响用户浏览器访问 Space。它仅接受无认证、无路径、无查询参数和无片段的 `http://` 或 `https://` 根代理地址,不支持 SOCKS。多渠道部署可用 `OPENAI_CHANNEL_N_PROXY_URL` 覆盖全局代理,渠道级值优先。代理地址即使不含凭据也建议作为 Space Secret 管理;修改后需要重新启动或重新部署 Space。运行态和 Agent 诊断只公开是否配置及协议,不公开主机或端口。
公网部署建议至少设置访问码 `APP_PASSWORD` 和 `AGENT_API_TOKEN`。如果不设置 `APP_PASSWORD`,任何人都可以打开网页并消耗服务端 API Key。
如果要把这个 Space 当成客户可见的公网服务,`npm run doctor:hf-space` 的 `remote-secrets` 必须通过,且应同时看到 `APP_PASSWORD` 和 `AGENT_API_TOKEN` 已配置。没有这两个值时,只适合本地或受控内网试用,不适合直接给客户公开。
如果使用服务端渠道池,改用 `OPENAI_CHANNEL_N_*` Secrets:
```dotenv
OPENAI_ROUTING_STRATEGY=round_robin
OPENAI_CHANNEL_1_ID=official
OPENAI_CHANNEL_1_BASE_URL=https://api.openai.com/v1
OPENAI_CHANNEL_1_API_KEYS=<key-a>,<key-b>
# 可选:仅覆盖此渠道的全局上游代理。
OPENAI_CHANNEL_1_PROXY_URL=http://channel-proxy.internal:8080
```
## 手机网页使用
1. 打开 Space 地址,例如 `https://<user>-<space>.hf.space`。
2. 如果配置了 `APP_PASSWORD`,输入页面访问码。
3. 直接填写提示词并生图。若 Space 没有配置服务端 API Key,也可以在右上角 `API 设置` 中填写自己的 API Key 和 API URL。
4. `NEXT_PUBLIC_IMAGE_STORAGE_MODE=indexeddb` 时,图片结果保存在当前浏览器 IndexedDB。换设备、清理浏览器数据或隐私模式退出后,本地历史可能消失。
## 电脑 Agent API 使用
先做只读契约检查,不触发真实生图:
```bash
GPT_IMAGE_PLAYGROUND_URL=https://<user>-<space>.hf.space \
GPT_IMAGE_AGENT_TOKEN=<agent-token> \
GPT_IMAGE_AGENT_CONTRACT_CHECK=1 \
node skills/gpt-image-playground-agent/scripts/generate-image.mjs
```
真实文生图:
```bash
GPT_IMAGE_PLAYGROUND_URL=https://<user>-<space>.hf.space \
GPT_IMAGE_AGENT_TOKEN=<agent-token> \
node skills/gpt-image-playground-agent/scripts/generate-image.mjs \
--allow-billable \
"a product photo of a ceramic mug on a wooden table"
```
脚本会先读取 `GET /api/agent/capabilities`,再调用 Agent API。成功响应会保留相对 `content_url`,同时补充 `absolute_content_url` 和 `absolute_metadata_url`,便于在桌面环境直接下载产物。
远端 Agent 调用不要硬编码路径。普通文生图默认提交业务意图到 capabilities 声明的 `orchestration.endpoint`,由服务端选择内部执行路径、上游 request mode 和轮询方式;Agent 客户端不按尺寸、远端 HTTPS 或流式参数自行选择 Images、Responses、SSE 或非流式路径。显式 page_sse 诊断、默认 WebP edit、高分辨率 edit 和复杂批量仍按 Skill 规则使用页面端 `/api/images` SSE;页面流式失败或不可用时,先诊断结构化错误,再用新的 `Idempotency-Key` 显式选择 Agent JSON、Agent edit 或 job 路径对照。job polling 只在显式选择时使用。需要诊断对照时可用 `--agent` 或 `--streaming-strategy off` 强制 Agent JSON,也可用 `--page-sse` 或 `--job` 显式选择路径。
如果 Space 同时配置了 `APP_PASSWORD` 和 `AGENT_API_TOKEN`,Agent JSON 端点用 `GPT_IMAGE_AGENT_TOKEN` 发送 Bearer token;页面端 `/api/images` SSE 仍按 capabilities 的 `agent_streaming.page_sse.auth` 判断,可能需要额外设置 `GPT_IMAGE_APP_PASSWORD_HASH`,并通过 form-data `passwordHash` 发送页面访问码哈希。页面 SSE 会把业务 key 写入 `clientRequestId`,长度上限以 capabilities 中的 `agent_streaming.page_sse.client_request_id.max_length` 为准。
## 本地 HF 近似 smoke
提交前运行:
```bash
npm run smoke:hf-space-local
```
该命令会:
- 使用 `NEXT_PUBLIC_IMAGE_STORAGE_MODE=indexeddb` 构建 Docker 镜像。
- 以 `AGENT_STATE_BACKEND=memory` 启动临时容器。
- 用手机 User-Agent 检查首页可访问。
- 检查 `/api/agent/capabilities` 返回 `state_backend=memory` 和 `image_storage_mode=indexeddb`。
- 默认等待容器 HTTP ready 最多 45 秒;慢机器可设置 `HF_SPACE_SMOKE_READY_TIMEOUT_MS=90000`。
- 执行 Agent 生成和编辑脚本的契约检查,不触发真实上游生图。
## 平台与运行限制
- Docker Space 的创建、更新和可用硬件受 Hugging Face 当前账户政策约束。`hf upload` 对已存在 Space 的创建接口检查收到 `402` 时,脚本会尝试认证 Git 推送;新建 Docker Space 仍需要满足平台账户要求。
- CPU Basic 适合公开演示和轻量使用,不适合长期高并发;长时间无访问后可能休眠。需要真正永不休眠或自定义 sleep time 时,应使用满足平台要求的付费硬件。
- Docker Space 重启后容器磁盘写入会丢失。`memory` 状态后端的 Agent 幂等记录、replay 状态和分享元数据也会丢失。
- Agent API 仍会把产物图片写入容器临时文件系统,以便提供 `content_url` 下载。重启后这些链接不保证继续有效。
- 需要长期保存图片、分享链接或 Agent replay 状态时,不应使用纯内存模式。应切换到 PostgreSQL 加持久卷或外部对象存储。
## 公网客户门槛
如果把 Space 对外提供给客户使用,至少要满足以下门槛:
- 先执行 `npm run deploy:space`,确保当前干净 git HEAD 已上传到固定 Space。
- 再用真实浏览器打开 Space,确认页面能进入并完成一次真实的浏览器检查。
- 仅有 `npm run doctor:hf-space` 的远端可达与 secret 检查,不足以证明客户可见上线。
- `APP_PASSWORD` 已设置,网页不会裸露给匿名访问者。
- `AGENT_API_TOKEN` 已设置,自动化调用不会回退到页面访问码哈希。
- `npm run doctor:hf-space` 的 `remote-secrets` 检查通过。
- 共享链接明确保留访问码和有效期的默认控制,不把无访问码永久链接当成默认发布形态。
- Space 重启丢失分享元数据和 Agent replay 的前提已被客户知晓。
## Space Keepalive
本仓库提供 GitHub Actions 定时 keepalive,降低 CPU Basic 因长时间无访问进入休眠的概率:
- 工作流文件:`.github/workflows/hf-space-keepalive.yml`
- 默认频率:每 6 小时一次,可手动触发 `workflow_dispatch`
- 默认目标:`https://misonl-visual-journal.hf.space/api/auth-status`
- GitHub Actions 使用 Node 26,并在最多 4 次请求中按 5 秒、10 秒、20 秒退避重试;每次超时 30 秒。失败日志会记录 HTTP 状态、响应类型和下一次等待时间,不把失败伪装成成功,也不会输出上游响应正文。
- 行为边界:只访问只读鉴权状态端点,不携带 `APP_PASSWORD`、`AGENT_API_TOKEN` 或 OpenAI Key,不触发生图、不访问 Agent 生成接口。
如果 Space 地址变化,在 GitHub 仓库 Variables 中设置:
```text
HF_SPACE_KEEPALIVE_URL=https://<user>-<space>.hf.space
```
本地手动验证:
```bash
HF_SPACE_KEEPALIVE_URL=https://<user>-<space>.hf.space \
HF_SPACE_KEEPALIVE_EXPECT_PASSWORD_REQUIRED=true \
HF_SPACE_KEEPALIVE_MAX_ATTEMPTS=4 \
HF_SPACE_KEEPALIVE_RETRY_DELAY_MS=5000 \
HF_SPACE_KEEPALIVE_RETRY_MAX_DELAY_MS=20000 \
npm run keepalive:hf-space
```
注意:keepalive 是 best-effort 机制,不能保证绕过 Hugging Face 平台维护、重启或政策限制。若需要平台级保证,应使用满足平台要求的硬件并设置永不休眠。
## 验证门禁
GitHub Actions 的 `.github/workflows/ci.yml` 会在 Pull Request、`main` 分支推送和手动触发时先核对锁文件安装脚本与 `allowScripts` 白名单、npm 的严格安装脚本能力,再以严格白名单模式安装依赖并核对直接依赖完整性,随后执行版本元数据检查、完整依赖审计、测试、源码 lint、脚本语法检查、生产构建、工作流 lint、Dockerfile 与基础 Compose 加 memory/PostgreSQL 覆盖配置检查。它还会构建和启动生产镜像后验证 `/api/auth-status`,并在独立 job 中运行真实 PostgreSQL 状态契约。
最小验证:
```bash
npm run install-scripts:check
npm run npm-install-policy:check
npm run dependencies:check
npm test
npm run lint
npm run lint:scripts
npm run build
npm run keepalive:hf-space
npm run smoke:hf-space-local
git diff --check
```
真实 Hugging Face gate:
1. 提交代码后执行 `npm run deploy:space`,等待 Space 新 commit 进入 `RUNNING`。
2. 用真实浏览器打开 Space,确认页面可进入并至少完成一次页面检查。
3. 电脑执行 `GPT_IMAGE_AGENT_CONTRACT_CHECK=1` 契约检查。
4. 如有可用测试额度,再执行一次真实 Agent 生成。
5. 重启 Space 后确认旧 Agent replay 和旧临时产物丢失符合预期。
6. 如果未执行第 1 步和第 2 步,必须在门禁报告里明确标注残余外部门禁未验证。