Qwen · 生成

提交异步视频任务;任务查询路径和响应格式因模型而异。

POST/v1/video/generations

异步任务

查看候选模型 ID
模型 ID厂商类型说明上下文窗口最大输出 Token媒体规格价格状态
happyhorse-1.1
Qwen视频多参考素材视频生成——
查看规格

型号:happyhorse-1.1

生成方式:参考生视频

查看价格

型号:happyhorse-1.1

$0.0391

币种:USD;计价单位:秒起;页面折扣:6折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
happyhorse-1.1-i2v
Qwen视频首帧图片结合提示词生成视频,音画同步——
查看规格

型号:happyhorse-1.1-i2v

生成方式:图生视频;音频生成:支持

查看价格

型号:happyhorse-1.1-i2v

$0.0391

币种:USD;计价单位:秒起;页面折扣:6折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
happyhorse-1.1-r2v
Qwen视频多参考图片生成视频,音画同步——
查看规格

型号:happyhorse-1.1-r2v

生成方式:参考生视频;参考素材上限:最多 9 张参考图像;音频生成:支持

查看价格

型号:happyhorse-1.1-r2v

$0.0391

币种:USD;计价单位:秒起;页面折扣:6折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
happyhorse-1.1-t2v
Qwen视频文本提示词生成视频,音画同步——
查看规格

型号:happyhorse-1.1-t2v

生成方式:文生视频;音频生成:支持

查看价格

型号:happyhorse-1.1-t2v

$0.0391

币种:USD;计价单位:秒起;页面折扣:6折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
wan2.6-i2v
Qwen视频万相2.6-图生视频,智能分镜调度支持多镜头叙事,更高品质的声音生成,多人稳定对话,更自然真实音色,最高支持15秒时长生成。—————
wan2.6-t2v
Qwen视频通义万相2.6-文生视频,智能分镜调度支持多镜头叙事,能够生成主体、场景和氛围一致的多镜头叙事视频,最高支持15秒时长,更高品质的声音生成。—————
wan2.7-i2v
Qwen视频图生视频——
查看规格

型号:wan2.7-i2v

生成方式:图生视频

查看价格

型号:wan2.7-i2v

$0.0827

币种:USD;计价单位:秒起;页面折扣:9.5折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
wan2.7-r2v
Qwen视频图像或视频混合参考,支持音频音色参考——
查看规格

型号:wan2.7-r2v

生成方式:参考生视频;参考素材上限:最多 5 个图像或视频混合参考;音频参考:支持

查看价格

型号:wan2.7-r2v

$0.0827

币种:USD;计价单位:秒起;页面折扣:9.5折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
wan2.7-t2v
Qwen视频文生视频——
查看规格

型号:wan2.7-t2v

生成方式:文生视频

查看价格

型号:wan2.7-t2v

$0.0827

币种:USD;计价单位:秒起;页面折扣:9.5折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
wan2.7-videoedit
Qwen视频自然语言局部或全局视频编辑,支持图像参考——
查看规格

型号:wan2.7-videoedit

生成方式:视频编辑

查看价格

型号:wan2.7-videoedit

$0.0827

币种:USD;计价单位:秒起;页面折扣:9.5折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—
wan3.0-video
Qwen视频文本、图片、音频、文档输入和音画同步——
查看规格

型号:wan3.0-video

生成方式:文生视频、图生视频;时长:最长 30 秒;分辨率:720P / 1080P;宽高比:9:16 / 16:9;音频生成:支持

查看价格

型号:wan3.0-video

$0.0326

币种:USD;计价单位:秒起;页面折扣:7.5折;资料日期:2026-09-28

登录页面参考价

登录模型广场展示价,含页面折扣;以当前账户价格和账单为准。

—

按公开标签归类,并补充模型广场资料;— 表示暂无明确资料。左右滑动查看完整表格。

进阶用法与完整流程 · 参数与透传

生成效果示例

Headers请求头

左右滑动查看完整参数表

请求头
参数名类型必填说明默认值 / 示例
Authorizationstring必填

平台 API Key,使用 Bearer 认证。

示例
Bearer YOUR_API_KEY
Content-Typestring必填

请求体编码格式。

示例
application/json

Request Body请求体

application/json

左右滑动查看完整参数表

请求体
参数名类型必填说明默认值 / 示例
modelstring必填

模型 ID;请替换为账户可用且支持当前接口的模型。

示例
MODEL_ID
promptstring可选

使用 prompt 格式的模型在此填写视频提示词。MiniMax-H3 使用顶层 content 数组中的 text 项,无需重复提供顶层 prompt。

—
imagestring可选

输入图片 URL 或 Base64;仅图生视频模型适用。

—
durationnumber可选

对 MiniMax-H3 必填

视频时长(秒),按具体模型填写整数。原生规格:Wan 3.0 为 2–30 秒,Seedance 2.5 文生为 4–30 秒,HappyHorse 1.1 文生为 3–15 秒,MiniMax-H3 为 4–15 秒,Veo 3.1 为 4/6/8 秒。

—
secondsstring可选

兼容视频协议的时长字符串。若同时填写 seconds 与 duration,两者应使用相同秒数。

示例
4
resolutionstring可选

对 MiniMax-H3 必填

模型专用分辨率字符串。Seedance 2.5 使用 480p/720p/1080p,Wan 3.0 与 HappyHorse 1.1 使用 480P/720P/1080P,MiniMax-H3 使用 768P/2K,Veo 3.1 的参考值为 720p。字段支持情况因模型和通道而异,最终尺寸以输出文件为准。

—
ratiostring可选

MiniMax-H3 文生视频(content 仅含 text)必填顶层 ratio,取 21:9、16:9、4:3、1:1、3:4、9:16,不能使用 adaptive。官方图生视频按输入图片自适应;其他模型的参数位置见 metadata。

示例
16:9
sizestring可选

宽x高形式的兼容尺寸,例如 1280x720;仅适用于支持此字段的模型。

示例
1280x720
contentarray可选

对 MiniMax-H3 必填

MiniMax-H3 原生内容数组。文生视频在顶层提供 type=text 的文本项,下列子字段描述文本项格式。

—
content[] 的子字段 2
content[] 子字段
参数名类型必填说明默认值 / 示例
typestring必填

内容项类型;纯文本项填写 text。

示例
text
textstring必填

该文本项的视频提示词。MiniMax-H3 必须包含一个非空文本项,最长 7000 字符,无需重复填写顶层 prompt。

—
widthinteger可选

输出宽度;需模型支持。

—
heightinteger可选

输出高度;需模型支持。

—
fpsinteger可选

输出帧率;需模型支持。

—
seedinteger可选

随机种子;需模型支持。

—
ninteger可选

生成数量;需模型支持。

—
response_formatstring可选

响应格式;由具体视频接口决定。

—
userstring可选

应用内用户标识;需接口支持。

—
metadataobject可选

模型专用扩展参数。Seedance/Veo 使用扁平字段,Wan/HappyHorse 使用 parameters 嵌套字段;各模型的结构不可互换。MiniMax-H3 的 ratio/content 放在顶层。

—
metadata 的子字段 8
metadata 子字段
参数名类型必填说明默认值 / 示例
resolutionstring可选

扁平分辨率字段,例如 Seedance 的 480p、Veo 的 720p;支持范围按模型选择。

—
ratiostring可选

扁平宽高比字段,例如 Seedance 的 16:9。MiniMax-H3 使用顶层 ratio。

—
durationinteger可选

扁平时长字段。Seedance 文生视频最低 4 秒,与顶层 duration/seconds 保持一致。

—
generate_audioboolean可选

Seedance 同步音频开关,false 表示请求不生成同步音频。此字段不用于独立语音合成。

示例
false
aspectRatiostring可选

Veo 原生宽高比,例如 16:9。

—
durationSecondsinteger可选

Veo 原生时长,例如 4,单位为秒。

—
numberOfVideosinteger可选

Veo 原生视频数量,例如 1。

—
parametersobject可选

Wan 与 HappyHorse 的嵌套参数对象;Wan 同时需要顶层 resolution。

—
metadata.parameters 的子字段 5
metadata.parameters 子字段
参数名类型必填说明默认值 / 示例
resolutionstring可选

Wan/HappyHorse 的分辨率选项,例如 480P、720P、1080P。是否采用请求值取决于模型和通道,输出尺寸以实际文件为准。

—
ratiostring可选

Wan/HappyHorse 的宽高比,例如 16:9;可选值按模型选择。

示例
16:9
durationinteger可选

HappyHorse 的视频时长,整数 3–15 秒,与顶层 duration/seconds 保持一致。

—
prompt_extendboolean可选

Wan 提示词扩写选项,false 表示请求关闭扩写;是否生效取决于模型和通道支持。

示例
false
audioboolean可选

Wan 音轨选项,false 表示请求关闭音频;是否生效取决于通道支持,最终音轨以输出文件为准。

示例
false

使用说明

  • 各模型的时长、分辨率与音轨选项不同,最终规格以输出文件为准,费用以账户账单为准。
  • Seedance/Veo 的扁平 metadata 与 Wan/HappyHorse 的 metadata.parameters 嵌套结构不可互换。
  • MiniMax-H3 使用 model、content、resolution、duration;文生视频还需顶层 ratio。提示词只填入 content 的 text 项,无需额外提供 prompt、seconds 或 metadata。
  • Doubao-Seedance-2.5 文生视频最低 4 秒。
  • 创建受理与生成完成是两个阶段:保存返回的任务 ID,再以低频 GET /v1/video/generations/{task_id} 查询同一任务;任务完成后读取结果地址。
  • 请求超时不等于服务端未创建任务;先检查已有任务 ID、提交记录或任务列表,避免重复提交。

创建、轮询与获取结果

创建请求只提交一次,并立即保存响应中的任务 ID。以下示例先等待 3 秒,再按 5、10、30 秒的间隔查询,之后保持 30 秒间隔;轮询预算为 600 秒。这些数值是客户端示例策略,不是平台频率限制或生成时长承诺。超时后保留任务 ID,后续继续查询同一任务。HTTP 错误、失败、取消及未知状态会停止本轮轮询。

阶段可能的响应位置处理方式
排队status=queued;data.status=NOT_START;output.task_status=PENDING继续查询已有任务
处理中data.status=IN_PROGRESS;嵌套 status=running继续查询已有任务
成功data.status=SUCCESS;嵌套 status=succeeded / task_status=SUCCEEDED读取结果地址并下载
失败或取消FAILURE / failed / cancelled停止轮询,读取 fail_reason / error
结果地址result_url、content.video_url、output.video_url、task.content.url按返回的 HTTPS URL 下载

先把所选模型的完整 JSON 请求体保存为 video-request.json。模型的时长、分辨率、content 与 metadata 结构各不相同,按本页对应模型填写。查询成功的 code=success 不等于视频任务成功。

展开 Python:一次创建、有界轮询与保存视频
Python
# 安装依赖:python -m pip install requests
import json
import os
import tempfile
import time
from pathlib import Path
from urllib.parse import quote, urlsplit
import requests

BASE_URL = "https://ai.kedang.net"

def normalize_task(payload):
    """读取任务状态;HTTP 200 或 code=success 仅表示查询成功。"""
    if not isinstance(payload, dict):
        raise ValueError("任务响应必须为 JSON 对象")
    if payload.get("error"):
        return {"state": "failed", "url": "", "reason": str(payload["error"])}
    code = payload.get("code")
    if code is not None and str(code).lower() not in ("0", "200", "success", "ok"):
        raise RuntimeError(payload.get("message") or str(code))
    nodes, layer = [payload], [payload]
    for _ in range(5):
        children = []
        for node in layer:
            for key in ("data", "output", "task", "content"):
                if isinstance(node.get(key), dict):
                    children.append(node[key])
        nodes.extend(children)
        layer = children
    # 外层任务状态优先;未提供时再读取嵌套状态。
    raw = next((str(node.get("status") or node.get("task_status")).lower()
                for node in nodes if node.get("status") or node.get("task_status")), "")
    states = {
        "queued": "queued", "pending": "queued", "not_start": "queued", "submitted": "queued",
        "in_progress": "running", "running": "running", "processing": "running",
        "success": "succeeded", "succeeded": "succeeded", "completed": "succeeded",
        "failure": "failed", "failed": "failed", "fail": "failed", "error": "failed", "expired": "failed",
        "cancelled": "cancelled", "canceled": "cancelled",
    }
    url = next((node[key] for node in nodes for key in ("result_url", "video_url", "url")
                if isinstance(node.get(key), str) and node[key]), "")
    reason = next((str(node[key]) for node in nodes for key in ("fail_reason", "error", "message")
                   if node.get(key)), "")
    return {"state": states.get(raw, "unknown"), "url": url, "reason": reason}


def poll_task(task_id, fetch, sleep, monotonic, total_timeout=600):
    """3 / 5 / 10 / 30 秒间隔与 600 秒预算均为客户端示例策略。"""
    if not isinstance(task_id, str) or not task_id:
        raise ValueError("任务 ID 不能为空")
    if total_timeout <= 0:
        raise ValueError("轮询预算必须大于零")
    encoded_id = quote(task_id, safe="")
    deadline = monotonic() + total_timeout
    delays, attempt = (3, 5, 10, 30), 0
    while True:
        remaining = deadline - monotonic()
        if remaining <= 0:
            raise TimeoutError("轮询超时,保留此 ID 后续查询:" + task_id)
        sleep(min(delays[min(attempt, len(delays) - 1)], remaining))
        remaining = deadline - monotonic()
        if remaining <= 0:
            raise TimeoutError("轮询超时,保留此 ID 后续查询:" + task_id)
        payload = fetch(encoded_id, min(30, remaining))
        if monotonic() >= deadline:
            raise TimeoutError("轮询超时,保留此 ID 后续查询:" + task_id)
        task = normalize_task(payload)
        if task["state"] == "succeeded":
            return payload
        if task["state"] in ("failed", "cancelled"):
            raise RuntimeError("任务 " + task_id + ":" + task["state"] + " " + task["reason"])
        if task["state"] not in ("queued", "running"):
            raise RuntimeError("未知任务状态,请按任务 ID 检查响应:" + task_id)
        attempt += 1

def download_video(url, target, headers=None):
    parsed = urlsplit(url)
    if parsed.scheme != "https" or not parsed.netloc:
        raise ValueError("下载地址必须为有效 HTTPS URL")
    target = Path(target)
    temporary = None
    try:
        with requests.get(url, headers=headers or {}, stream=True, timeout=(10, 120)) as response:
            response.raise_for_status()
            mime = response.headers.get("Content-Type", "").split(";", 1)[0].lower()
            if mime and not (mime.startswith("video/") or mime == "application/octet-stream"):
                raise ValueError("下载响应不是视频或二进制文件")
            with tempfile.NamedTemporaryFile(dir=target.parent, delete=False) as file:
                temporary = Path(file.name)
                size = 0
                for chunk in response.iter_content(chunk_size=1024 * 1024):
                    if chunk:
                        file.write(chunk)
                        size += len(chunk)
            if size == 0:
                raise ValueError("下载内容为空")
        temporary.replace(target)
    finally:
        if temporary is not None:
            temporary.unlink(missing_ok=True)
    return target

def main():
    headers = {"Authorization": "Bearer " + os.environ["KEDANG_API_KEY"]}
    # 将所选模型的完整创建请求保存到此 JSON 文件,包含它要求的规格与扩展参数。
    body = json.loads(Path("video-request.json").read_text(encoding="utf-8"))
    if not body.get("model") or body["model"] == "MODEL_ID":
        raise ValueError("请在 video-request.json 中填写账户可用的模型与完整请求参数")
    # 创建只提交一次。网络超时时先核对任务记录,避免重复创建。
    created_response = requests.post(BASE_URL + "/v1/video/generations", headers=headers,
                                     json=body, timeout=(10, 120))
    created_response.raise_for_status()
    created = created_response.json()
    if created.get("error"):
        raise RuntimeError(created["error"])
    data = created.get("data") if isinstance(created.get("data"), dict) else {}
    task_id = created.get("task_id") or created.get("id") or data.get("task_id")
    if not isinstance(task_id, str) or not task_id:
        raise RuntimeError("响应没有任务 ID;保留提交记录,不自动重新创建。")
    Path("video-task-id.txt").write_text(task_id, encoding="utf-8")
    print("任务 ID:", task_id)

    def fetch(encoded_id, timeout):
        response = requests.get(BASE_URL + "/v1/video/generations/" + encoded_id,
                                headers=headers, timeout=timeout)
        response.raise_for_status()
        return response.json()

    result = poll_task(task_id, fetch, time.sleep, time.monotonic, total_timeout=600)
    url = normalize_task(result)["url"]
    if not url:
        raise RuntimeError("任务已成功但缺少结果地址;使用保存的任务 ID 查询。")
    # 返回的媒体 URL 可能在独立域名,下载时不发送平台 Authorization。
    print(download_video(url, "video.mp4"))

if __name__ == "__main__":
    main()