# H3 视频生成队列网关（MiniMax H3 Ref2VA）

这是一个 24 小时在线的生成队列。任务先在网关排队，攒够一批后，网关自动开一台 Colab G4（RTX PRO 6000），从网盘恢复 wenwu2 ComfyUI（文武双修 H3 工作流），跑完自动关机。所以**提交后不会马上开始生成**：通常要等凑批，再加约 15 分钟的 G4 恢复时间。

- **Base URL**：`https://h3.zirun.me`（固定域名，不会变）
- **鉴权**：除 `GET /` 和 `/health` 外，所有请求都要带 `Authorization: Bearer <API_KEY>`。每个用户一个 Key，由管理员在面板「用户管理」里创建。
- **主控面板**：浏览器打开 `https://h3.zirun.me/dashboard`，输入 API Key 登录。管理员能看到全部任务，可以调整顺序、开关 G4、改开机策略、管理用户和审核模型；普通用户只能看到和取消自己的任务。
- **网页提交**：浏览器打开 `https://h3.zirun.me/submit`，用同一个 API Key 登录，拖入参考图（≤9）和音频（≤3）、写提示词、设时长画幅后直接提交；单张图超过 6MB 会在浏览器里压缩，单次提交合计不超过 90MB。
- **内容审核**（按用户开关）：开启后，任务先进入 `reviewing`，由审核模型检查提示词和全部素材。违规的变成 `rejected`：素材和提示词在网关上删除，**不会存入网盘**，`error` 里写明类别和原因。审核模型连续出错时也会拒绝（fail-closed），这种情况管理员可以人工放行。
- **网盘存档**（按用户开关）：开启时请求、素材和成片存到网盘 `H3_Gateway/日期/用户名/…`；关闭后只留在网关本机。开关只影响之后提交的任务。
- **开机条件**：等待中的任务 ≥ 3 个，或最早的任务已经等了 20 分钟。队列空 15 分钟后 G4 自动关闭（重新开机要约 15 分钟，太早关反而更费）。
- **项目**：提交时带 `project`，可以按项目查看进度、成片秒数和花掉的 CU，也可以一次取消整个项目。
- **CU 计费**：每个成功的任务记 `cu.gpu`（生成用的 GPU 时间 × 费率）；G4 关机后，开机、恢复和空闲的时间按 GPU 时间比例摊到这次会话的任务上，记为 `cu.overhead`。

## 接口（兼容 h3api 的提交和查询方式）

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/v1/jobs` | 提交任务，请求体见下文 |
| GET | `/v1/jobs/{id}` | 查询任务状态 |
| GET | `/v1/jobs/{id}/video` | 下载 mp4 |
| DELETE | `/v1/jobs/{id}` | 取消任务 |
| GET | `/v1/jobs?limit=100&project=名称` | 列出任务：`active` 是排队中和生成中的任务（按执行顺序），`recent` 是最近结束的任务；`project` 可选 |
| GET | `/v1/projects` | 项目列表：各状态任务数、成片秒数、CU 合计 |
| GET | `/v1/projects/{name}` | 单个项目的统计和全部任务 |
| DELETE | `/v1/projects/{name}` | 取消这个项目所有未完成的任务 |
| POST | `/v1/jobs/{id}/move` | 调整排队顺序，请求体为 `{"to":"top|up|down|bottom"}`、`{"position":n}` 或 `{"before":"<job_id>"}` |
| GET | `/v1/me` | 当前 Key 对应的用户、角色、审核和存档设置 |
| GET | `/v1/status` | 查看队列计数、G4 状态；管理员另外能看到开机策略、Colab 余额和网盘同步状态 |
| GET / POST | `/v1/config` | 读取或修改开机策略：`auto_start`（默认 false，只能管理员 `POST /v1/worker/start` 开机）、`batch_min`（默认 20）、`max_wait_min`、`idle_stop_min`、`max_session_hours`、`max_inflight`、`health_grace_min`、`boot_timeout_min`、`max_variants` |
| POST | `/v1/worker/start` | 有任务排队时立即开 G4，不等凑批 |
| POST | `/v1/worker/stop` | 关闭 G4，未完成的任务退回队列 |

调整顺序、`/v1/config`、`/v1/worker/*` 以及下面的接口只有管理员 Key 能用：

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET / POST | `/v1/users` | 列出用户（Key 打码），或创建用户：`{"name","role":"user|admin","moderation":true,"moderation_model":null,"persist":true,"note":"","key":"可选"}`，返回完整 Key |
| PATCH | `/v1/users/{name}` | 修改 `name`（改名）、`role`、`enabled`、`moderation`、`moderation_model`、`persist`、`note` |
| GET | `/v1/users/{name}/key` | 查看完整 Key |
| POST | `/v1/users/{name}/rotate` | 重置 Key，旧 Key 立即失效 |
| DELETE | `/v1/users/{name}` | 删除用户，历史任务保留 |
| GET / POST | `/v1/moderation` | 审核设置：`categories`（类别列表）、`default_model`、`prefilter_keywords`、`fail_closed` |
| POST | `/v1/moderation/models` | 新增或修改审核模型：`{"id","name","provider":"agy|anthropic|keywords","model","api_key","effort","timeout","words","enabled"}` |
| DELETE | `/v1/moderation/models/{id}` | 删除审核模型（默认模型和仍分配给用户的模型不能删） |
| POST | `/v1/moderation/test` | 试审一段内容：`{"model","prompt","images":[…]}` |
| POST | `/v1/jobs/{id}/approve` | 人工放行因审核服务故障被拒绝的任务（真正违规的任务素材已删除，不能放行） |

审核模型三种类型：`agy` 用本机 Gemini 命令行，能看图、听音频、看视频，每次约 15–30 秒；`anthropic` 用 Claude API，审核提示词、图片和视频抽帧，不审音频，需要 `anthropic` SDK 和 API Key；`keywords` 是本地关键词表，即时返回，可以作为前置过滤。

### 提交任务 `POST /v1/jobs`

```json
{"title": "可选，面板里显示的任务名", "prompt": "H3 六字段提示词…", "images": ["https://…/a.png", {"base64": "…", "filename": "b.png"}],
 "audios": [{"base64": "…", "filename": "voice.wav"}], "seconds": 5, "aspect": "9:16", "megapixels": 0.5,
 "seed": 1, "variants": 2, "project": "一面之恩-第3集", "callback_url": "https://example.com/h3-done"}
```

- `images` 必填，最多 9 张；`audios` 最多 3 段，按数组顺序对应 `<Picture N>`、`<Audio N>`。**暂不支持参考视频**，带 `videos` 会返回 400。
- 每个素材可以写成公网 URL，也可以写成 `{"base64": "...", "filename": "..."}`。
- `seconds` 范围 1–20 秒。
- 画幅：`aspect` 可选 `1:1 2:3 3:2 3:4 4:3 9:16 16:9 21:9`，默认 `9:16`；`megapixels` 是放大前的基础尺寸（0.1–0.85，默认 0.5），工作流最后会再放大 1.2 倍，0.5 的竖屏成片约 650×1150。仍兼容旧的 `width`/`height`（按成片尺寸理解），网关会换算成最接近的画幅和尺寸。
- `seed` 不填就随机。`variants`（1–4）同一镜头一次出几个不同种子，返回 `{"batch", "project", "jobs":[…]}`；`variants` 为 1 时返回单个任务，和以前一样。
- `project` 是项目或批次名，用来分组统计。
- `callback_url`：任务结束（成功、失败、取消）时网关向这个公网地址 POST `{"event":"job.succeeded","job":{…}}`，失败会重试 3 次。

### 任务状态

`status` 依次可能是：
- `reviewing`：内容审核中（仅开启审核的用户），通过后变成 `queued`，不通过变成 `rejected`；
- `queued`：在网关排队，附 `queue_position` 和 `worker`（G4 状态）；
- `dispatched`：已转给 G4；
- `running`：G4 正在生成；
- 最终是 `succeeded`（附 `video_url`）、`failed`（附 `error`）、`cancelled` 或 `rejected`（审核未通过，附 `error` 和 `moderation`）。被拒绝的任务原样重新提交还会被拒绝。

每个任务还会返回 `progress`（0–1）、`stage`（当前阶段的文字说明），生成中的任务另外返回 `eta_seconds`。生成进度是按已完成任务的实际速度估算的。

如果 G4 中途被回收，未完成的任务会自动退回队列重试，最多重试 3 次。网络短暂抖动不会关机：G4 连不上超过 6 分钟、并且确认 Colab 会话已经没了，才退回队列。

建议每 30–60 秒轮询一次。任务可能要排队几十分钟，这是正常的。

## curl 示例

```bash
BASE=https://h3.zirun.me; KEY=<API_KEY>
JOB=$(curl -s -X POST $BASE/v1/jobs -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d @job.json | python3 -c 'import json,sys;print(json.load(sys.stdin)["job_id"])')
curl -s $BASE/v1/jobs/$JOB -H "Authorization: Bearer $KEY"
curl -s -o out.mp4 $BASE/v1/jobs/$JOB/video -H "Authorization: Bearer $KEY"
```

## TODO

- 成片自动验收（时长、音轨、黑帧、口型等）：考虑到网关本机负载，暂不做，网关只负责交回成品。
- 参考视频输入：wenwu2 工作流还没接视频参考。
