HiAPI
博客

教程

FLUX 3 Max API:在 hiapi 上使用文本生成视频、图片生成视频与关键帧

三个模型 ID,一条 /v1/tasks 流程:curl、Python 辅助脚本、关键帧时间轴规则,以及真实的校验错误。

2026年11月3日
FLUX 3 Max API:在 hiapi 上使用文本生成视频、图片生成视频与关键帧

摘要

  • hiapi 上的 FLUX 3 Max 是同一个 POST /v1/tasks 端点上的三个独立模型 ID:flux-3-max/text-to-video、flux-3-max/image-to-video 和 flux-3-max/keyframes-to-video。切换模式只需更改 model 和一个输入字段。
  • 三者都能生成 5–20 秒、720p 或 1080p 的片段,按输出秒数和分辨率计费。实时价格请查看 /en/pricing。
  • 关键帧的帧号规则在提交时不会被检查。时间轴有误时接口仍会返回 HTTP 200 和 taskId,但任务会在约 2 秒后失败。请先在本地校验。

本指南针对 Max 档。带草稿模式和视频续写的基础 flux-3 模型见 FLUX.3 视频 API 指南,对现有素材进行编辑见 flux-3 视频编辑。

前提条件

在 hiapi 控制台创建密钥并导出:

export HIAPI_KEY=sk-your-key

所有模式的请求流程相同:POST /v1/tasks 返回 taskId,然后轮询 GET /v1/tasks/<taskId>(或使用回调),直到 status 为 success,再下载 data.output[0].url。

不同输入对应哪个模型 ID

你拥有的输入 模型 ID 需要更改的输入
只有文本提示词 flux-3-max/text-to-video prompt
一张静止图(可选再给一张尾帧) flux-3-max/image-to-video image_url,可选 end_image_url
1–10 张必须落在特定时刻的图片 flux-3-max/keyframes-to-video keyframes: [{image_url, frame_index}]

三者共用的可选字段:duration(整数秒,5–20,默认 5)、resolution(720p 或 1080p)、aspect_ratio(auto、21:9、2:1、16:9、4:3、1:1、3:4、9:16)、generate_audio(布尔值,默认开启)和 reasoning_level(low 或 high,默认 high)。模型页面:文本生成视频、图片生成视频、关键帧生成视频。

最小示例:用 curl 进行文本生成视频

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer $HIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-3-max/text-to-video",
    "input": {
      "prompt": "a slow aerial shot of ocean waves at sunrise, photorealistic",
      "duration": 5,
      "resolution": "720p",
      "generate_audio": false,
      "reasoning_level": "low"
    }
  }'

请求有效时返回 {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}。然后:

curl https://api.hiapi.ai/v1/tasks/tk-hiapi-... -H "Authorization: Bearer $HIAPI_KEY"

generate_audio 加上 5 秒 low 推理的配置,是比较提示词效果的廉价方式;模型页面说明音频不会改变价格。

一个 Python 辅助脚本覆盖全部三种模式

# pip install requests
import os, time, requests

KEY = os.environ["HIAPI_KEY"]
H = {"Authorization": f"Bearer {KEY}"}
BASE = "https://api.hiapi.ai/v1/tasks"

def submit(mode: str, **inp) -> str:
    """mode: text-to-video | image-to-video | keyframes-to-video"""
    body = {"model": f"flux-3-max/{mode}", "input": inp}
    res = requests.post(BASE, json=body, headers=H, timeout=30).json()
    if res.get("code") != 200:
        # sync 400s look like {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: ..."}
        raise RuntimeError(res)
    return res["data"]["taskId"]

def wait(task_id: str, timeout_s: int = 900, every: int = 10) -> str:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        d = requests.get(f"{BASE}/{task_id}", headers=H, timeout=30).json()["data"]
        if d["status"] == "success":
            return d["output"][0]["url"]
        if d["status"] == "fail":
            raise RuntimeError(d.get("error"))
        time.sleep(every)
    raise TimeoutError(task_id)

# 1) text-to-video
t2v = submit("text-to-video",
    prompt="A single white sneaker rotates slowly on a wet black plinth, studio softbox lighting, macro product shot",
    duration=5, resolution="720p", aspect_ratio="16:9", generate_audio=False)

# 2) image-to-video: first frame, optional last frame
i2v = submit("image-to-video",
    prompt="Morning mist drifts over the harbor; the boats rock gently and the camera slowly pushes forward.",
    image_url="https://example.com/harbor.jpg",
    # end_image_url="https://example.com/harbor-end.jpg",   # optional fixed ending
    duration=5, resolution="720p", generate_audio=False)

# 3) keyframes-to-video
FPS = 24
def keyframes_ok(duration: int, frames: list[dict]) -> None:
    idx = [f["frame_index"] for f in frames]
    assert 1 <= len(frames) <= 10, "1-10 keyframes"
    assert len(set(idx)) == len(idx), "frame_index must be unique"
    assert all(0 <= i <= duration * FPS for i in idx), f"frame_index must be 0..{duration * FPS}"

frames = [
    {"image_url": "https://example.com/harbor.jpg", "frame_index": 0},
    {"image_url": "https://example.com/latte.jpg",  "frame_index": 120},
]
keyframes_ok(5, frames)
kf = submit("keyframes-to-video",
    prompt="A continuous cinematic morph from the misty harbor into a close-up of an iced matcha latte.",
    keyframes=frames, duration=5, resolution="720p", generate_audio=False)

url = wait(kf)
open("clip.mp4", "wb").write(requests.get(url).content)

输出 URL 会过期,所以任务成功后应立即下载或复制文件,而不是保存链接。

关键帧:时间轴如何运作

frame_index 是从 0 开始的 24 fps 时钟上的位置,而不是百分比。允许的最大值为 duration × 24:5 秒为 120,10 秒为 240,20 秒为 480。索引必须唯一,可传 1 到 10 个关键帧。要实现干净的 A 到 B 过渡,把第一个锚点放在 0,最后一个放在 duration × 24;把最后一个锚点提前可保持结尾,推后可压缩变化。保持所有关键帧的宽高比一致;如需无缝循环,让首尾图像看起来像同一时刻。

生产环境注意事项

  • 轮询与回调。 任务 API 接受 callback.url 和 when: "final",这样就不必轮询;像上面那样每 10 秒轮询一次,对脚本和批处理任务来说也没问题。
  • 始终给轮询循环设置超时,并在轮询前持久化 taskId,以免程序崩溃导致已付费的任务丢失。
  • 立即下载。 将 output[0].url 视为短期有效。
  • 成本控制。 计费按输出秒数和分辨率计算,所以 20 秒 1080p 片段的成本是 5 秒 720p 测试的好几倍。先用 5 秒和 720p 做原型,提示词有效后再提升两者。当前费率见价格页面。

我测试了什么,没测试什么

这些检查于 2026 年 10 月 23 日使用只读测试密钥针对线上 API 进行。本文没有渲染完整片段,因此我不对输出质量做任何断言;示例提示词来自模型页面自带的示例。

同步校验(HTTP 400,未入队)。 超出范围的值在提交时即被拒绝,返回 error_code: INVALID_REQUEST 和可读的 message:

请求 响应 message
duration: 3 invalid input: duration: minimum: got 3, want 5
resolution: "4k" value must be one of '720p', '1080p'
aspect_ratio: "5:4" value must be one of 'auto', '21:9', '2:1', '16:9', '4:3', '1:1', '3:4', '9:16'
reasoning_level: "medium" value must be one of 'low', 'high'
图片生成视频使用 image_urls 而非 image_url image_url: missing required field "image_url"; ... additional properties 'image_urls' not allowed

最后一行是常见错误:hiapi 其他图片输入模型使用复数字段,但 FLUX 3 Max 图片生成视频只接受单个 image_url。未知字段会被拒绝,而不是忽略。

关键帧时间轴错误是异步的。 我提交了两个 5 秒关键帧请求,时间轴都有问题:一个使用 frame_index: 121(超过 120 上限),另一个两个关键帧都在 frame_index: 0。两者都被接受,返回 HTTP 200 和 taskId。创建后约 1–2 秒轮询返回终态:

{"code":200,"data":{"status":"fail","model":"flux-3-max/keyframes-to-video",
 "error":{"code":"INVALID_REQUEST","message":"Invalid request parameters for this model. Please check the request and try again."},
 "taskId":"tk-hiapi-..."},"message":"success"}

由此可得两点。第一,提交返回 200 并不意味着时间轴有效,所以轮询时要检查 status 和 error.code。第二,失败消息很笼统,不会指出哪一帧有问题,这就是上面 keyframes_ok 检查值得在提交前运行的原因。模型页面说明失败任务不收费;我没有检查这两个任务的账单记录。

常见问题

首帧加尾帧应该用哪个模型 ID? 使用 flux-3-max/image-to-video,传入 image_url 和 end_image_url。只有需要在首尾之间设置锚点时才用关键帧。

增加关键帧会更贵吗? 根据模型页面,不会:计费按输出秒数和分辨率计算,锚点数量不影响价格。

这与 flux-3 有何区别? flux-3-max/* 是独立模型 ID,按模式拆分(文本、图片、关键帧);而基础 flux-3 是一个 ID,根据输入切换模式,还支持草稿模式和续写。参见 FLUX.3 视频 API 指南。我没有比较两者的输出质量,所以请根据功能和价格页面上的费率来选择。

可以改用其他图片生成视频模型吗? 可以。其他图片生成视频方案见 如何使用 Ray 3.2 图片生成视频 API。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档