在一张 RTX 5090 上运行的 MiniMax-H3 视频生成服务。文生视频、图生视频(1 到 6 张图),输出 24 fps 带立体声的 mp4。任务在单卡上顺序执行,新任务自动排队。
| 公网 | https://desktop-lp9ii17.tail97a7d2.ts.net |
|---|---|
| 本机 | http://127.0.0.1:8000 |
所有 /api/* 请求都需要口令,三种传法任选一种:
| 推荐 | Authorization: Bearer <TOKEN> 请求头 |
|---|---|
| 备选 | x-token: <TOKEN> 请求头 |
| 备选 | ?token=<TOKEN> 查询参数 |
口令错误或缺失返回 401 {"detail":"bad token"}。口令保存在服务器的 webapp/config.json,修改后重启服务生效。已开启 CORS,浏览器页面可以直接跨域调用。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/v1/generate | 用 JSON 创建任务。文生视频,或图生视频(图片给 URL 或 base64)。可选同步等待、完成回调。 |
| POST | /api/jobs | 同上,multipart 表单版本,图片作为文件字段 images(可多个)。网页就是用的这个。 |
| GET | /api/jobs | 任务列表,最新在前。 |
| GET | /api/jobs/{id} | 单个任务。加 ?wait=true&timeout=600 会阻塞到完成或超时。 |
| GET | /api/jobs/{id}/video | 下载成品 mp4(H.264 + AAC 立体声 32 kHz)。 |
| DELETE | /api/jobs/{id} | 排队中:取消;生成中:中断;已完成:删除任务和文件。 |
| GET | /api/status | ComfyUI 是否在线、当前任务 id、排队数。 |
| GET | /api/config | 可用的模型方案、尺寸表、时长选项。 |
| GET | /out/{id}.mp4 | 成品的静态地址(可直接放进 <video src>,无需口令)。 |
POST /api/v1/generate请求体 JSON,所有字段除 prompt 外都可省略:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
prompt | string | 必填 | 画面、镜头运动和声音的描述,中英文均可。引号里的台词会做口型同步。 |
profile | string | fasth3 | fasth3 画质最好(8 步)· turbo_int8 均衡(8 步)· fasth3_4step_int8 最快(4 步) |
aspect | string | 16:9 | 16:9 · 9:16 · 1:1 |
res | string | 480p | 352p · 480p · 768p,实际像素见下方尺寸表 |
seconds | number | 5 | 1 到 15 秒。帧数会向上取整到模型的 17k+5 帧网格(24 fps),例如 5 秒 → 124 帧 = 5.17 秒 |
seed | int | -1 | -1 表示随机。相同参数和 seed 可复现 |
steps | int | 0 | 0 表示用方案默认(8 或 4),一般不用改 |
images | string[] | [] | 0 到 6 张。每项是 https://… 图片地址,或 data:image/png;base64,…。1 张 = 首帧;2 张 = 首帧 + 末帧;3 到 6 张 = 首帧、末帧,其余按顺序均匀锚定到时间轴。图片会被缩放裁切到目标画幅 |
wait | bool | false | true 时请求阻塞到任务完成再返回最终任务对象 |
timeout | int | 600 | wait 的最长等待秒数,上限 1800;超时返回当时的状态(任务继续跑) |
callback_url | string | 无 | 任务结束(成功或失败)后把任务对象 POST 到这个地址,JSON 格式 |
返回值就是任务对象;不带 wait 时立即返回,状态为 queued。
POST /api/jobs字段名与上表相同(prompt, profile, aspect, res, seconds, seed, steps),图片放在一个或多个 images 文件字段里。不支持 wait 和 callback_url,拿到 id 后用 GET /api/jobs/{id}?wait=true 等待即可。
{
"id": "20260918_202901_6197",
"status": "queued | running | done | failed",
"prompt": "…", "profile": "fasth3", "mode": "t2v | i2v",
"aspect": "16:9", "res": "480p", "size": "864x480",
"seconds": 5.0, "frames": 124, "seed": 1234, "steps": 8, "image_count": 0,
"created": 1789731030.1,
"position": 1, // queued:队列位置(1 = 下一个)
"progress": {"value": 3, "max": 8}, // running:采样步进度
"stage": "采样", "elapsed": 12.3, // running:当前阶段、已用秒数
"exec_s": 24.7, // done:生成耗时(秒)
"video": "/out/20260918_202901_6197.mp4", // done:可直接播放的静态地址
"video_download": "/api/jobs/20260918_202901_6197/video", // done:带文件名的下载地址
"finished": 1789731060.2,
"error": "…", // failed:原因
"callback_status": 200 // 设置了 callback_url 时:回调的 HTTP 状态
}
stage 依次经过:加载模型 → 加载文本编码器 → 编码提示词/图片 → 采样 → 视频解码 → 音频解码 → 封装 → 保存。模型只在切换方案时重新加载。
| 352p | 480p | 768p | |
|---|---|---|---|
| 16:9 | 608×352 | 864×480 | 1344×768 |
| 9:16 | 352×608 | 480×864 | 768×1344 |
| 1:1 | 480×480 | 672×672 | 1024×1024 |
| profile | 步数 | 特点 |
|---|---|---|
fasth3 | 8 | FastH3 8 步完整模型,画质最好,默认 |
turbo_int8 | 8 | Turbo LoRA,风格略不同,速度相近 |
fasth3_4step_int8 | 4 | 最快,细节稍软 |
时长:任意 1 到 15 秒,网页上给的是 5 / 8 / 10 / 15。
RTX 5090,fasth3 8 步,实测每条片子的生成耗时(不含排队):
| 分辨率 | 5 秒 | 10 秒 | 采样速度 | 备注 |
|---|---|---|---|---|
| 352p | ≈ 13 s | ≈ 26 s | 1.8 s/步 | 预览、快速试提示词 |
| 480p | ≈ 27 s | ≈ 54 s | 4.5 s/步 | 速度与可看度的折中 |
| 768p | ≈ 90 s | ≈ 178 s | 18.2 s/步 | 最高画质,10 秒片显存接近 32 GB 上限 |
fasth3_4step_int8 采样步数减半,整体约快 30% 到 40%。切换方案的第一条任务多 3 到 10 秒加载时间。同一时间只跑一个任务,排队时间 = 前面任务的耗时之和。
curl -s https://desktop-lp9ii17.tail97a7d2.ts.net/api/v1/generate \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"prompt":"一只戴墨镜的小熊猫在舞台上打鼓,暖色聚光灯,观众欢呼,电影感。声音:鼓点、欢呼声。","res":"480p","seconds":5,"wait":true}'
# 返回的 JSON 里 status 为 done 时:
curl -L -o clip.mp4 -H "Authorization: Bearer <TOKEN>" \
https://desktop-lp9ii17.tail97a7d2.ts.net/api/jobs/<id>/video
curl -s https://desktop-lp9ii17.tail97a7d2.ts.net/api/v1/generate \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"prompt":"镜头缓慢推进,画面从第一帧过渡到最后一帧。声音:轻柔的风声。",
"images":["https://example.com/first.png","https://example.com/last.png"],
"res":"480p","seconds":5}'
# → {"id":"2026…","status":"queued",…}
curl -s -H "Authorization: Bearer <TOKEN>" \
"https://desktop-lp9ii17.tail97a7d2.ts.net/api/jobs/<id>?wait=true&timeout=600"
curl -s https://desktop-lp9ii17.tail97a7d2.ts.net/api/jobs \
-H "Authorization: Bearer <TOKEN>" \
-F "prompt=The scene comes alive, gentle camera drift. Audio: ambient." \
-F "res=480p" -F "seconds=5" \
-F "images=@first.png" -F "images=@middle.png" -F "images=@last.png"
import base64, time, requests
BASE = "https://desktop-lp9ii17.tail97a7d2.ts.net"
H = {"Authorization": "Bearer <TOKEN>"}
def data_uri(path):
return "data:image/png;base64," + base64.b64encode(open(path, "rb").read()).decode()
job = requests.post(f"{BASE}/api/v1/generate", headers=H, json={
"prompt": "A golden retriever puppy runs through autumn leaves, slow motion. Audio: leaves crunching.",
"images": [data_uri("first.png")], # 可省略 → 文生视频
"res": "480p", "seconds": 5, "seed": 42,
}).json()
while job["status"] in ("queued", "running"):
time.sleep(3)
job = requests.get(f"{BASE}/api/jobs/{job['id']}", headers=H).json()
print(job["status"], job.get("position"), job.get("stage"), job.get("progress"))
if job["status"] == "done":
mp4 = requests.get(BASE + job["video_download"], headers=H).content
open("clip.mp4", "wb").write(mp4)
print("saved, generation took", job["exec_s"], "s")
else:
print("failed:", job.get("error"))
const BASE = "https://desktop-lp9ii17.tail97a7d2.ts.net";
const r = await fetch(BASE + "/api/v1/generate", {
method: "POST",
headers: { "Authorization": "Bearer <TOKEN>", "Content-Type": "application/json" },
body: JSON.stringify({ prompt: "城市夜景航拍,霓虹反射在湿润的街道上。声音:车流、雨声。", res: "352p", seconds: 5, wait: true })
});
const job = await r.json();
if (job.status === "done") document.querySelector("video").src = BASE + job.video; // /out/… 不需要口令
提交时带 "callback_url": "https://你的服务器/hook",任务结束后会向该地址 POST 一份任务对象(成功和失败都会发)。video 是相对路径,拼上 BASE 即可下载;回调的 HTTP 状态会记录在任务的 callback_status。
| 状态码 | 含义 |
|---|---|
400 | 参数错误:未知 profile / aspect / res,prompt 为空,seconds 不在 1 到 15,图片下载失败或格式不对,图片超过 25 MB。detail 里有原因 |
401 | 口令缺失或错误 |
404 | 任务不存在,或视频尚未生成完成 |
422 | JSON 字段类型不对(FastAPI 校验),返回里逐字段说明 |
position 是队列位置。error 带 ComfyUI 的异常信息;服务重启会把未完成的任务标记为失败。DELETE /api/jobs/{id} 删除。