无限画布无限画布
GPU API工具箱 API 文档Proxy Base URL(画布内部)视频类

视频脱衣

视频脱衣组合 GPU API 的请求、阶段、轮询与错误说明

文档更新时间:2026年09月08日 12时53分18秒(UTC+8)

视频脱衣(组合 API)

最后更新:2026-09-07

项目值
modelvideo-undress
输入1 个源视频
内部 SchedulerPOST /v1/video-undress
输出1 个经过媒体校验的视频

组合流程

首帧提取 → Krea2 图片脱衣 → 新首帧 → Wan2.1 SCAIL2

创建任务

curl -X POST "$BASE_URL/api/proxy/v1/videos" \
  -H "Cookie: ic_session=$IC_SESSION" \
  -H "X-IC-Operation-ID: $(uuidgen)" \
  -F "model=video-undress" \
  -F "prompt=保持原视频动作、镜头运动和节奏" \
  -F "seed=12345" \
  -F "input_reference[]=@source.mp4"

源视频支持 MP4/MOV、最大 500MB,并须包含可解码音轨;人物图支持 JPG/PNG/BMP/WEBP、单张最大 30MB。Proxy 会按 MIME 分类,不把文件名后缀当作唯一判断。

状态与结果

  1. 创建成功保存返回的 id。
  2. POST /api/proxy/v1/videos/{id} 轮询 pending/running/completed/failed。
  3. 完成后调用 GET /api/proxy/v1/videos/{id}/content 下载视频。
  4. 取消调用 POST /api/proxy/v1/videos/{id}/cancel;只有服务端确认取消后才视为终止。

完整 Python 调用

下面代码可直接保存为 call_video_undress.py。先执行 pip install requests,再设置 BASE_URL、IC_SESSION 并准备示例媒体。代码会提交任务、轮询、下载最终 MP4;若存在首帧预处理结果,也会下载为 intermediate.png。

import mimetypes
import os
import time
import uuid
from contextlib import ExitStack
from pathlib import Path

import requests

BASE_URL = os.environ.get("BASE_URL", "https://ic.xshow.live").rstrip("/")
IC_SESSION = os.environ["IC_SESSION"]
MODEL = "video-undress"
POLL_SECONDS = 5
TIMEOUT_SECONDS = 6 * 60 * 60

session = requests.Session()
session.cookies.set("ic_session", IC_SESSION)


def mime(path: str) -> str:
    value = mimetypes.guess_type(path)[0]
    if not value:
        raise ValueError(f"无法识别媒体 MIME: {path}")
    return value


def checked(response: requests.Response) -> requests.Response:
    if not response.ok:
        raise RuntimeError(f"HTTP {response.status_code}: {response.text[:1000]}")
    return response


with ExitStack() as stack:
    files = [
        ("input_reference[]", (Path("source.mp4").name, stack.enter_context(open("source.mp4", "rb")), mime("source.mp4")))
    ]
    created = checked(session.post(
        f"{BASE_URL}/api/proxy/v1/videos",
        headers={"X-IC-Operation-ID": str(uuid.uuid4())},
        data={
            "model": MODEL,
            "prompt": "保持原视频动作、镜头运动和节奏",
            "seed": "12345",
        },
        files=files,
        timeout=1800,
    )).json()

task_id = created.get("id") or (created.get("data") or {}).get("id")
if not task_id:
    raise RuntimeError(f"创建响应缺少任务 ID: {created}")
print("task_id:", task_id)

deadline = time.time() + TIMEOUT_SECONDS
while time.time() < deadline:
    state = checked(session.post(
        f"{BASE_URL}/api/proxy/v1/videos/{task_id}",
        timeout=60,
    )).json()
    status = str(state.get("status") or (state.get("data") or {}).get("status") or "pending").lower()
    print("status:", status)
    if status == "completed":
        video = checked(session.get(
            f"{BASE_URL}/api/proxy/v1/videos/{task_id}/content",
            timeout=1800,
        ))
        Path("result.mp4").write_bytes(video.content)
        print("saved: result.mp4")

        payload = state.get("data") if isinstance(state.get("data"), dict) else state
        if payload.get("intermediate_image_available") is True:
            intermediate = checked(session.get(
                f"{BASE_URL}/api/proxy/v1/videos/{task_id}/intermediate",
                timeout=600,
            ))
            Path("intermediate.png").write_bytes(intermediate.content)
            print("saved: intermediate.png")
        break
    if status in {"failed", "cancelled", "canceled", "expired"}:
        raise RuntimeError(f"任务失败: {state}")
    time.sleep(POLL_SECONDS)
else:
    raise TimeoutError(f"任务 {task_id} 超过 {TIMEOUT_SECONDS} 秒仍未完成")

阶段失败

错误会保留首帧提取、图片预编辑、SCAIL2 提交、GPU 执行或结果校验阶段的真实原因。400 通常是媒体数量/格式错误,503 是工作流未就绪,502 是上游或结果媒体校验失败。

On this page