共绩科技
共绩科技

预制服务

minimax-h3 turbo + RTX VSR 合并镜像使用说明

一个镜像 =minimax-H3 生视频服务(ComfyUI:8188)+ 视频超分服务(VSR API:8001),单张 RTX 5090(32GB)跑通「768p 生成 → 2K 超分」全链路,产物带音轨

一、快速开始:5 步跑通全链路

Step 1 — 探活(两个服务各一次)

curl -s $COMFY/system_stats        # 返回 200 + JSON 即活(ComfyUI 无 /health)
curl -s $VSR/healthz               # {"status":"ok","service":"rtxvsr",...}

Step 2 — 提交一条 H3 生成任务(768p / 5 秒 / 4 步 turbo)

# workflow JSON 太长,完整版见第四节,这里示意提交方式:
curl -s -X POST $COMFY/prompt \
  -H "Content-Type: application/json" \
  -d '{"prompt": {…workflow…}, "client_id": "my-app-1"}'
# → {"prompt_id": "7498f8fe-…", "number": 1, "node_errors": {}}

⚠️ node_errors 非空 = 工作流有错,根本没入队

Step 3 — 轮询到 success,下载 768p 产物

curl -s $COMFY/history/7498f8fe-… | jq '.[].status.status_str'   # "success"
# 从 outputs 里拿 filename,然后:
curl -s -o h3_raw.mp4 "$COMFY/view?filename=<文件名>&subfolder=&type=output"

Step 4 — 提交超分任务(2 倍放大 → 2688×1536)

curl -s -X POST $VSR/api/v1/upscale/file \
  -F "file=@h3_raw.mp4" -F "scale=2.0" -F "quality=HIGH" \
  -F "vcodec=libx264"
# → {"task_id":"d1247542e667","status":"queued","poll":"/api/v1/tasks/…"}

⚠️ 共绩平台必须用 vcodec=libx264(节点 NVENC 当前不可用,详见 5.4 节)。本地/自建机器可用默认 h264_nvenc。

Step 5 — 轮询 done,下载 2K 产物

curl -s $VSR/api/v1/tasks/d1247542e667       # {"status":"done","meta":{"total_s":30.9,…}}
curl -s -o h3_2k.mp4 $VSR/api/v1/tasks/d1247542e667/result

⚠️ /result 返回的是 video/mp4 二进制流(带 Content-Disposition 头),不是 JSON——直接当文件下载。

二、镜像概览与启动模式

项内容
基础镜像minimax-h3 turbo 官方预制(ComfyUI 0.31.0 + int8 DiT×2 + turbo 4-step LoRA + qwen3vl 文本编码器 + 双 VAE)
附加层RTX VSR(nvidia-vfx/Maxine VFX)FastAPI 服务、cupy-cuda12x 运行栈、python-multipart
显存生成峰值 ~27.8GB;超分峰值 ~6-10.5GB(随分辨率)
启动配置ENTRYPOINT=/entrypoint-merge.sh,CMD=both

启动模式(run 参数选一个)

模式行为什么时候用
both(默认)ComfyUI(8188) + VSR(8001) 双进程一体机(注意显存叠加,见下)
comfyui仅 ComfyUI纯生成节点
vsr仅 VSR API纯超分节点(可部署在便宜机器上)
selftest依次自检 cupy→nvvfx→VSR→NVENC 后退出部署后冒烟验证(一次性容器)

显存布局(both 模式,同卡)

ComfyUI(H3):  峰值 ~27.8 GiB(模型 int8 ~20G + 文本编码器 nvfp4 ~15G 走 CPU offload + KV)
VSR:          逐任务 ~6-10.5 GiB

三、部署

3.1 预制镜像

3.2 共绩 openapi 部署

① 查资源拿 mark(mark 是资源标识,随库存变动,每次部署前查):

curl -s "https://openapi.suanli.cn/api/deployment/resource/search" \
  -H "token: <你的API密钥>" -H "version: 1.0.0" -H "timestamp: <毫秒时间戳>"
# 找到 "device_name":"5090" + "region":"tj1q"(天津一区)的那条,
# 记下 results[i].regions[0].mark(一长串 base64)和 resource 对象

② 创建任务:

{
  "task_name": "h3vsr_merge_014",
  "points": 1,
  "repository_username": "bala",
  "repository_password": "<bala账号密码>",
  "resources": [{
    "mark": "<第①步查到的mark>",
    "resource": {"device_name": "5090", "region": "tj1q", "gpu_name": "5090",
                  "gpu_count": 1, "gpu_memory": 32600, "memory": 64512, "cpu_cores": 16},
    "region_name": "天津一区",
    "weight": null
  }],
  "services": [{
    "service_name": "h3vsr-svc",
    "service_image": "harbor.suanleme.cn/bala/h3vsr-merge:0.1.4-5090",
    "env": [{"name": "NVIDIA_DRIVER_CAPABILITIES", "value": "compute,utility,video"}],
    "remote_ports": [{"service_port": 8188}, {"service_port": 8001}],
    "start_script_v2": {"command": null, "args": []},
    "resource_weight": {"cpu_weight": 1, "mem_weight": 1, "gpu_weight": 1}
  }]
}
curl -s -X POST "https://openapi.suanli.cn/api/task/deployment/create" \
  -H "token: <密钥>" -H "version: 1.0.0" -H "timestamp: <毫秒>" \
  -H "Content-Type: application/json" --data-binary @payload.json
# → {"code":"0000","data":{"task_id":3402316}}

③ 轮询到 Running,拿公网 URL:

curl -s "https://openapi.suanli.cn/api/task/deployment/detail?task_id=3402316" \
  -H "token: …" -H "version: 1.0.0" -H "timestamp: …"
# data.status == "Running",data.services[0].remote_ports[].url 就是两个公网地址

四、服务 A:H3 文生视频

4.1 探活

ComfyUI 没有 /health 端点,探活用 GET /system_stats(HTTP 200 即活)。刚启动 1~3 分钟内可能拒绝连接(模型链加载中),重试即可。

4.2 T2V 工作流(权威版,逐节点注释)

这是实测跑通的 turbo 4-step 工作流。为什么是这五个采样节点:H3 的 turbo LoRA 要求 CFG=1.0,此时不需要 negative 分支,用 SamplerCustomAdvanced 五节点链(RandomNoise→BasicGuider→KSamplerSelect→BasicScheduler→SamplerCustomAdvanced)替代普通 KSampler——普通 KSampler 也能跑但这套是官方 turbo 工作流的原版结构,参数语义最清晰。

{
  "10": {"class_type": "UNETLoader", "inputs": {
      "unet_name": "minimax_h3_fl2va_pruned_int8_convrot.safetensors",
      "weight_dtype": "default"}},
  "11": {"class_type": "LoraLoaderModelOnly", "inputs": {
      "model": ["10", 0],
      "lora_name": "minimax_h3_fl2v_turbo_4step_v1.0_768p_comfyui_bf16.safetensors",
      "strength_model": 1.0}},
  "12": {"class_type": "MiniMaxH3SigmaShift", "inputs": {
      "model": ["11", 0], "shift_video": 12.0, "shift_audio": 3.0}},
  "13": {"class_type": "CLIPLoader", "inputs": {
      "clip_name": "qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors",
      "type": "minimax", "device": "default"}},
  "14": {"class_type": "VAELoader", "inputs": {"vae_name": "minimax_h3_video_vae_fp16.safetensors"}},
  "15": {"class_type": "VAELoader", "inputs": {"vae_name": "minimax_h3_audio_vae_fp32.safetensors"}},

  "16": {"class_type": "MiniMaxH3ImageToVideo", "inputs": {
      "clip": ["13", 0], "vae": ["14", 0],
      "prompt": "Cinematic anime style, a red sports car drifting through a neon-lit Tokyo street at night, rain-slick asphalt reflections, motion blur. Audio: engine roar, tire screech.",
      "width": 1344, "height": 768, "length": 124}},

  "20": {"class_type": "RandomNoise", "inputs": {"noise_seed": 123456}},
  "21": {"class_type": "BasicGuider", "inputs": {"model": ["12", 0], "conditioning": ["16", 0]}},
  "22": {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}},
  "23": {"class_type": "BasicScheduler", "inputs": {
      "model": ["12", 0], "scheduler": "simple", "steps": 4, "denoise": 1.0}},
  "24": {"class_type": "SamplerCustomAdvanced", "inputs": {
      "noise": ["20", 0], "guider": ["21", 0], "sampler": ["22", 0],
      "sigmas": ["23", 0], "latent_image": ["16", 1]}},

  "30": {"class_type": "VAEDecode", "inputs": {"samples": ["24", 0], "vae": ["14", 0]}},
  "31": {"class_type": "VAEDecodeAudio", "inputs": {"samples": ["24", 0], "vae": ["15", 0]}},
  "32": {"class_type": "CreateVideo", "inputs": {"images": ["30", 0], "audio": ["31", 0], "fps": 24.0}},
  "33": {"class_type": "SaveVideo", "inputs": {
      "video": ["32", 0], "filename_prefix": "H3VSR", "format": "auto", "codec": "auto"}}
}

节点说明:

  • 10-15 加载器链:DiT(int8) → turbo LoRA → sigma shift(turbo 专用,shift 参数勿乱动)→ 文本编码器 → 双 VAE(视频/音频分开)
  • 16 生成参数全在这里(见下表);注意它输出两个值:conditioning(接 21)和 latent(接 24)
  • 20-24 采样链:4 步 euler + CFG 隐含 1.0(BasicGuider 只接 positive 就是 CFG=1)
  • 30-33 解码成片:视频 VAE + 音频 VAE 分别解码 → 合成 mp4(fps=24,H3 原生帧率)

4.3 生成参数表

参数含义可选值与约束
width/height分辨率必须 32 的倍数。常用:864×480(480p)/ 1280×720(720p)/ 1344×768(768p,推荐) / 1920×1080(1080p,32G 卡 10s/15s 会 OOM)
length帧数(24fps)必须落在 17k+5 网格:5s=124、10s=243、15s=362。校验式:(length-5) % 17 == 0 且 124 ≤ length ≤ 362
prompt提示词同时描述画面和音轨(“Audio: …”),H3 生成同步音频

⚠️ 帧数网格是最容易踩的坑:提交非法值(如 245)不会报错,节点静默向上取整(245→260 帧),多花时间且超出训练范围质量下降。实测记录:提交 245 实际生成 260 帧、365→379 帧。

⚠️ 产物帧数 = 请求 +3(H3 帧数补偿):请求 124 实际 127 帧,属正常,不是 bug。

⚠️ 防缓存:同参数同 seed 第二次提交会命中执行缓存秒回旧结果。批量跑每条要随机 seed(改节点 20 的 noise_seed)。

4.4 提交、轮询、下载

POST /prompt          body: {"prompt": <workflow>, "client_id": "<任意ID>"}
  → {"prompt_id": "...", "node_errors": {}}     # node_errors 非空=工作流有错没入队
GET  /history/{prompt_id}
  → status.status_str: "success" / "error"
  → outputs.{node_id}.gifs[] / videos[]: [{filename, subfolder, type}]
GET  /view?filename=<名>&subfolder=<子目录>&type=output   → 文件流

错误详情:status_str=error 时看 status.messages 里的 execution_error,有节点名和异常栈。

性能基准(5090 单卡 turbo 4-step,实测 P50):

分辨率5s10s15s
480p38s65s117s
720p75s168s375s
768p81~138s243s452s(接近 OOM 边界)

(768p/5s 的区间:本地热态 80.1s、本地冷启动 110.2s、共绩远程冷启动 138.2s)

4.5 参考生视频(R2V)

T2V 换三处成 R2V 链,其余不变:

节点T2V(默认)R2V
10 unet_namefl2vaminimax_h3_ref2va_pruned_int8_convrot.safetensors
11 lora_namefl2v_turbo…v1.0minimax_h3_ref2v_turbo_4step_v0.1_comfyui_bf16.safetensors
16 class_typeMiniMaxH3ImageToVideoMiniMaxH3ReferenceToVideo(多必填 audio_vae: ["15",0])

R2V 关键点(实测):

  • 参考图上传:POST /upload/image(multipart,字段名 image),客户端超时设 ≥600s(35MB 大图用默认 120s 会 write timeout)
  • ref_images 接线:API 里是列表:"ref_images": [["201",0], ["202",0]];写成 ref_image_1 会报 TypeError: unexpected keyword argument
  • 提示词前部用 <Picture 1>、<Picture 2> 引用参考图
  • fl2va ↔ ref2va 模型切换有 ~124s 冷加载(同进程内来回切很亏,尽量按模型分组批量跑)

五、服务 B:VSR 视频超分

超分 API 文档位置:部署链接+ /docs

5.1 接口一览

方法路径用途
GET/healthz健康检查
POST/api/v1/upscale/filemultipart 直传视频
GET/api/v1/tasks/{id}状态轮询
GET/api/v1/tasks/{id}/result下载产物

5.2 参数详解

curl -X POST $VSR/api/v1/upscale/file \
  -F "file=@input.mp4" \      # 必填:输入视频(mp4/h264 最佳;带音轨会原样保留)
  -F "scale=2.0" \            # 放大倍数,支持小数(1.5 实测 OK);768p→2K 用 2.0
  -F "quality=HIGH" \         # 质量档,见下表
  -F "vcodec=libx264" \       # 编码器,见 5.4 节(平台差异!)
  -F "bitrate=50M"            # 输出码率,2K 建议 50M

quality 枚举(非法值返回 400 “bad quality”):

值速度用途
BICUBIC最快不跑模型,纯插值(自检链路用)
LOW / MEDIUM快预览
HIGH中768p AI 生成源推荐
ULTRA略慢与 HIGH 差距很小(13.5s vs 10.1s),可选
HIGHBITRATE_*-高码率源专用

status 轮询响应:

{"task_id":"…","status":"done","progress":1.0,"error":null,
 "meta":{"total_s":30.9,"size_mb":54.3,"quality":"HIGH","scale":2.0}}

status 取值:queued → running → done | error。error 时 error 字段是完整异常文本。

5.3 错误码实测

请求响应
scale=“abc”422 + {"detail":[{"loc":["body","scale"],"msg":"Input should be a valid number…"}]}
缺 file 字段422
quality=“NOT_A_LEVEL”400 “bad quality”(worker 层校验,提交时是 200 queued,稍后 error)⚠️ 即:quality 错误是异步暴露的,轮询时才能看到
task_id 不存在404

5.4 并发

/healthz 的 concurrency.max=3,但同卡 both 模式下受显存约束实际安全并发=1(生成空闲时)。queue_visible 是「已提交未开始」数,不是队列深度,别当监控用。


六、全链路整合:完整可运行客户端

单文件、纯标准库、带超时与错误处理。覆盖典型场景:探活 → 生成(校验帧数网格)→ 下载 → 超分(自动选编码器)→ 下载 → 校验。。

#!/usr/bin/env python3
"""h3vsr-merge 全链路客户端:H3 生成 768p -> VSR 2x 超分 -> 2K mp4
用法: python h3vsr_client.py "提示词" [输出目录]
依赖: 仅 Python 标准库
"""
import json, time, random, sys, os, urllib.request, urllib.parse, uuid

# ========== 配置(按你的部署改这两行) ==========
COMFY = "https://deployment-452-xxxx-8188.550w.link"
VSR   = "https://deployment-452-xxxx-8001.550w.link"
VCODEC = "libx264"        # 共绩平台用 libx264;本地机器可改回 h264_nvenc
# ================================================

# --- 帧数网格校验(H3 硬约束,防静默取整多耗时间)---
def valid_length(n):
    return (n - 5) % 17 == 0 and 124 <= n <= 362

def build_workflow(prompt, width=1344, height=768, length=124, seed=None):
    """构造 T2V 工作流。分辨率须 32 倍数,帧数须 17k+5 网格(124/243/362)。"""
    assert width % 32 == 0 and height % 32 == 0, "宽高必须是 32 的倍数"
    assert valid_length(length), "length 必须是 124/243/362(17k+5 网格)"
    return {
      "10": {"class_type": "UNETLoader", "inputs": {
          "unet_name": "minimax_h3_fl2va_pruned_int8_convrot.safetensors", "weight_dtype": "default"}},
      "11": {"class_type": "LoraLoaderModelOnly", "inputs": {
          "model": ["10", 0],
          "lora_name": "minimax_h3_fl2v_turbo_4step_v1.0_768p_comfyui_bf16.safetensors",
          "strength_model": 1.0}},
      "12": {"class_type": "MiniMaxH3SigmaShift", "inputs": {
          "model": ["11", 0], "shift_video": 12.0, "shift_audio": 3.0}},
      "13": {"class_type": "CLIPLoader", "inputs": {
          "clip_name": "qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors",
          "type": "minimax", "device": "default"}},
      "14": {"class_type": "VAELoader", "inputs": {"vae_name": "minimax_h3_video_vae_fp16.safetensors"}},
      "15": {"class_type": "VAELoader", "inputs": {"vae_name": "minimax_h3_audio_vae_fp32.safetensors"}},
      "16": {"class_type": "MiniMaxH3ImageToVideo", "inputs": {
          "clip": ["13", 0], "vae": ["14", 0], "prompt": prompt,
          "width": width, "height": height, "length": length}},
      "20": {"class_type": "RandomNoise", "inputs": {
          "noise_seed": seed if seed is not None else random.randint(1, 2**48)}},  # 每条随机,防缓存秒回
      "21": {"class_type": "BasicGuider", "inputs": {"model": ["12", 0], "conditioning": ["16", 0]}},
      "22": {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}},
      "23": {"class_type": "BasicScheduler", "inputs": {
          "model": ["12", 0], "scheduler": "simple", "steps": 4, "denoise": 1.0}},
      "24": {"class_type": "SamplerCustomAdvanced", "inputs": {
          "noise": ["20", 0], "guider": ["21", 0], "sampler": ["22", 0],
          "sigmas": ["23", 0], "latent_image": ["16", 1]}},
      "30": {"class_type": "VAEDecode", "inputs": {"samples": ["24", 0], "vae": ["14", 0]}},
      "31": {"class_type": "VAEDecodeAudio", "inputs": {"samples": ["24", 0], "vae": ["15", 0]}},
      "32": {"class_type": "CreateVideo", "inputs": {"images": ["30", 0], "audio": ["31", 0], "fps": 24.0}},
      "33": {"class_type": "SaveVideo", "inputs": {
          "video": ["32", 0], "filename_prefix": "h3vsr_client", "format": "auto", "codec": "auto"}},
    }

def http_json(url, data=None, method=None, timeout=120):
    req = urllib.request.Request(url, method=method)
    if data is not None:
        req.add_header("Content-Type", "application/json")
        req.data = json.dumps(data).encode()
    with urllib.request.urlopen(req, timeout=timeout) as r:
        return json.loads(r.read())

def download(url, path, timeout=1800):
    with urllib.request.urlopen(url, timeout=timeout) as r, open(path, "wb") as f:
        while True:
            chunk = r.read(1 << 20)
            if not chunk: break
            f.write(chunk)

def wait_comfy(pid, poll_s=15, limit_s=3000):
    """轮询 ComfyUI 到 success/error。5s 片约 80-140s,15s 片留足 50 分钟。"""
    t0 = time.time()
    while time.time() - t0 < limit_s:
        time.sleep(poll_s)
        hist = http_json(f"{COMFY}/history/{pid}", timeout=60)
        if pid in hist:
            st = hist[pid]["status"]["status_str"]
            if st == "error":
                msgs = hist[pid]["status"].get("messages", [])
                raise RuntimeError(f"H3 生成失败: {json.dumps(msgs, ensure_ascii=False)[:800]}")
            if st == "success":
                return hist[pid]
        print(f"  ...生成中 {int(time.time()-t0)}s", flush=True)
    raise TimeoutError("H3 生成超时")

def comfy_output(entry):
    """从 history 里抠出产物文件(优先 mp4)。"""
    files = []
    for node_out in entry.get("outputs", {}).values():
        for key in ("gifs", "videos", "images", "audio"):
            files.extend(node_out.get(key, []))
    mp4 = next((f for f in files if f["filename"].endswith(".mp4")), None)
    if not mp4:
        raise RuntimeError(f"产物里没有 mp4: {files}")
    return mp4

def vsr_upscale(src_path, scale=2.0, quality="HIGH"):
    """multipart 提交超分并轮询到 done,返回 task_id。"""
    boundary = uuid.uuid4().hex
    with open(src_path, "rb") as f: filedata = f.read()
    parts = [f'--{boundary}\r\nContent-Disposition: form-data; name="file"; filename="{os.path.basename(src_path)}"\r\nContent-Type: video/mp4\r\n\r\n'.encode()
             + filedata + b"\r\n"]
    for k, v in [("scale", str(scale)), ("quality", quality), ("vcodec", VCODEC)]:
        parts.append(f'--{boundary}\r\nContent-Disposition: form-data; name="{k}"\r\n\r\n{v}\r\n'.encode())
    parts.append(f"--{boundary}--\r\n".encode())
    req = urllib.request.Request(f"{VSR}/api/v1/upscale/file", data=b"".join(parts), method="POST")
    req.add_header("Content-Type", f"multipart/form-data; boundary={boundary}")
    with urllib.request.urlopen(req, timeout=600) as r:
        up = json.loads(r.read())
    tid = up["task_id"]
    t0 = time.time()
    while time.time() - t0 < 1800:      # 软编忙时可达 100s/5s片,15s 片留 30 分钟
        time.sleep(8)
        st = http_json(f"{VSR}/api/v1/tasks/{tid}", timeout=60)
        if st["status"] == "error":
            raise RuntimeError(f"超分失败: {st.get('error','')[:500]}")
        if st["status"] == "done":
            print(f"  超分完成: {st['meta']}", flush=True)
            return tid
        print(f"  ...超分 {st['status']} {int(time.time()-t0)}s", flush=True)
    raise TimeoutError("超分超时")

def main():
    prompt = sys.argv[1] if len(sys.argv) > 1 else "Cinematic anime style, a red sports car drifting through neon-lit Tokyo street at night. Audio: engine roar, rain ambience."
    outdir = sys.argv[2] if len(sys.argv) > 2 else "."
    os.makedirs(outdir, exist_ok=True)

    # 0) 探活(ComfyUI 冷启动 1-3 分钟,重试 5 次)
    for i in range(5):
        try:
            http_json(f"{COMFY}/system_stats", timeout=30); break
        except Exception:
            if i == 4: raise
            print("ComfyUI 未就绪,30s 后重试…", flush=True); time.sleep(30)
    http_json(f"{VSR}/healthz", timeout=30)

    # 1) 生成(产物帧数 = 请求 +3 属正常)
    t0 = time.time()
    resp = http_json(f"{COMFY}/prompt", {"prompt": build_workflow(prompt), "client_id": "h3vsr-client"})
    if resp.get("node_errors"):
        raise RuntimeError(f"工作流校验失败: {json.dumps(resp['node_errors'], ensure_ascii=False)[:500]}")
    entry = wait_comfy(resp["prompt_id"])
    gen_s = time.time() - t0
    f = comfy_output(entry)
    q = urllib.parse.urlencode({"filename": f["filename"], "subfolder": f.get("subfolder",""), "type": f.get("type","output")})
    raw = os.path.join(outdir, "h3_raw.mp4")
    download(f"{COMFY}/view?{q}", raw)
    print(f"✅ 生成 {gen_s:.0f}s → {raw} ({os.path.getsize(raw)/1e6:.1f}MB)")

    # 2) 超分(串行:生成完才提交,单卡显存安全)
    t1 = time.time()
    tid = vsr_upscale(raw)
    dst = os.path.join(outdir, "h3_2k.mp4")
    download(f"{VSR}/api/v1/tasks/{tid}/result", dst)     # /result 是 mp4 流
    print(f"✅ 超分 {time.time()-t1:.0f}s → {dst} ({os.path.getsize(dst)/1e6:.1f}MB)")
    print(f"🎉 全链路 {time.time()-t0:.0f}s")

if __name__ == "__main__":
    main()

八、故障排查速查表

症状原因解法
C001 body is errorpayload 结构错 / 客户端重编码 null按 3.1 模板;curl —data-binary @file
A001 must need token…header 缺失或时间戳过期三件套(token/version/timestamp)每次现取
ComfyUI 提交即 node_errors 非空工作流节点名/参数错对照 4.2 权威版;最常见是 length 不在网格、模型文件名抄错(带 comfyui_bf16 后缀勿截断)
生成帧数比请求多 3 帧H3 帧数补偿正常
生成秒回但结果是旧片执行缓存命中(同 seed)每条随机 seed
VSR 报 OpenEncodeSessionEx failed平台节点 NVENC 不可用vcodec=libx264(共绩);本地不受影响
VSR JSON 模式任务永久 pendingvideo_url 拉取无超时卡死 worker一律用 multipart /upscale/file
quality 明明错了却不报 422校验在 worker 层,异步暴露轮询 status==error 看 error 字段
生成中提交超分 → OOM单卡显存叠加(27.8+10.5>32G)串行:生成完再超分(第六节客户端已处理)
/result 解析 JSON 报错它返回的是 mp4 二进制流按文件流下载

九、附录

A. 内置模型清单

/comfyui/ComfyUI/models/diffusion_models/
  minimax_h3_fl2va_pruned_int8_convrot.safetensors      # T2V DiT (int8, ~21GB)
  minimax_h3_ref2va_pruned_int8_convrot.safetensors     # R2V DiT (int8, ~21GB)
/comfyui/ComfyUI/models/loras/
  minimax_h3_fl2v_turbo_4step_v1.0_768p_comfyui_bf16.safetensors
  minimax_h3_ref2v_turbo_4step_v0.1_comfyui_bf16.safetensors
/comfyui/ComfyUI/models/vae/
  minimax_h3_video_vae_fp16.safetensors                 # 视频 VAE
  minimax_h3_audio_vae_fp32.safetensors                 # 音频 VAE
/comfyui/ComfyUI/models/clip/
  qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors          # 文本编码器 (nvfp4, ~15.7GB)