HiAPI
博客

教程

如何通过 hiapi API 使用 omnihuman-1.5:curl、Python 与可直接运行的请求

2026年11月3日
如何通过 hiapi API 使用 omnihuman-1.5:curl、Python 与可直接运行的请求

omnihuman-1.5 可将一张人像照片加上一段音频,生成口型同步的说话视频。在 hiapi 上,它与其他所有媒体模型一样,运行在同一套异步任务协议上:先调用一次 POST /v1/tasks 创建任务,然后轮询(或接收 webhook)直到视频 URL 就绪。本指南使用真实的请求 schema——已与线上 API 逐字段核对——因此下面的 curl 和 Python 代码可以直接复制运行,而不只是示例。

你将构建什么

一个脚本,将人脸图像和语音轨道发送给 omnihuman-1.5,返回一个该人脸按照音频说话、口型同步的 MP4 文件。视频片段长度跟随你的音频——没有 duration 字段可设置。

前提条件

  1. 一个 hiapi API key。 在 dashboard 中创建一个;每次请求都会作为 Bearer token 发送。请求头格式请参阅 认证文档。
  2. 一个可公开访问的图像 URL 和音频 URL。 omnihuman-1.5 会在服务端下载两者,因此你的机器能匿名打开的 http(s) URL 即可;localhost 路径和任务中途过期的签名 URL 则不行。

就这些——不需要 SDK,除 key 之外不需要账户。

输入 schema

omnihuman-1.5 接受严格的 input 对象。未知字段会被拒绝,因此这就是全部可用字段:

字段 类型 是否必填 说明
image_url string 是 一张人像 URL。清晰、正面的单张人脸效果最好。
audio_url string 是 用于口型同步的语音轨道。决定输出长度。
prompt string 否 可选的动效/表情引导。
resolution string 否 "720p" 或 "1080p"。

没有纯文本模式:audio_url 是必填的。如果你只有脚本,请先生成语音(使用 TTS 模型,或像 heygen-avatar-v 这样的文本驱动数字人),然后将生成的音频 URL 传到这里。

最小可运行示例(curl)

创建任务:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "omnihuman-1.5",
    "input": {
      "image_url": "https://example.com/portrait.jpg",
      "audio_url": "https://example.com/voiceover.mp3",
      "resolution": "720p"
    }
  }'

响应中带有任务 id:

{ "code": 200, "data": { "taskId": "b3f1c2e8-...", "status": "pending" } }

轮询任务,直到它达到终止状态:

curl -s https://api.hiapi.ai/v1/tasks/b3f1c2e8-... \
  -H "Authorization: Bearer sk-YOUR_KEY"

完成后,data.status 为 "success",视频位于 data.output[0].url:

{
  "code": 200,
  "data": {
    "taskId": "b3f1c2e8-...",
    "status": "success",
    "output": [
      { "url": "https://temp.hiapi.ai/.../omnihuman.mp4", "expireAt": 1760000000 }
    ]
  }
}

该 output URL 是临时的(带有 expireAt)。任务成功后应立即下载 MP4——不要在生产环境中直接热链该地址。

Python 中的同样调用

import time
import requests  # pip install requests

API = "https://api.hiapi.ai/v1/tasks"
KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}


def create_task() -> str:
    payload = {
        "model": "omnihuman-1.5",
        "input": {
            "image_url": "https://example.com/portrait.jpg",
            "audio_url": "https://example.com/voiceover.mp3",
            "resolution": "720p",
        },
    }
    r = requests.post(API, headers=HEADERS, json=payload, timeout=60)
    r.raise_for_status()
    return r.json()["data"]["taskId"]


def wait_for_video(task_id: str, timeout: int = 600, interval: int = 5) -> str:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30)
        data = r.json()["data"]
        status = data["status"]
        if status == "success":
            return data["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"omnihuman-1.5 task failed: {data.get('error')}")
        time.sleep(interval)
    raise TimeoutError(f"task {task_id} did not finish in {timeout}s")


if __name__ == "__main__":
    tid = create_task()
    print("task:", tid)
    video_url = wait_for_video(tid)
    # URLs expire — persist the bytes immediately.
    mp4 = requests.get(video_url, timeout=120).content
    with open("talking_head.mp4", "wb") as f:
        f.write(mp4)
    print("saved talking_head.mp4")

投入生产

优先使用回调而不是密集轮询。 添加一个顶层 callback 对象,hiapi 就会将完成的任务 POST 到你的端点,而不是让你轮询:

{
  "model": "omnihuman-1.5",
  "input": {
    "image_url": "https://example.com/portrait.jpg",
    "audio_url": "https://example.com/voiceover.mp3",
    "resolution": "1080p"
  },
  "callback": { "url": "https://your.app/webhooks/hiapi", "when": "final" }
}

when 只接受 "final",并且会在成功和失败时都触发——因此你的 webhook 必须根据 data.status 分支处理。投递的 body 与通过 GET /v1/tasks/{id} 得到的是同一个对象。投递是至少一次语义,因此请按 taskId 去重。

绝不要在临时错误上重新提交。 如果轮询请求超时或连接中断,请重新轮询同一个 taskId——不要再次调用 POST /v1/tasks。重新提交会启动第二个计费任务。拿到 taskId 后立即保存。

分别处理三种失败形态:

  • 认证失败 → HTTP 401,body {"error": {"code": "permission_denied", "type": "hiapi_error", ...}}。修复 key;不要重试。
  • 错误请求(缺少/无效字段)→ HTTP 400,body {"code": 400, "error_code": "INVALID_REQUEST", "message": "..."}。message 会指出有问题的字段——修复后重新发送。
  • 已启动但失败的任务 → HTTP 200,且 data.status == "fail",并带有 data.error。最常见的原因是服务端无法下载 image_url/audio_url。请检查两者均可公开访问且仍然有效。始终根据 data.status 分支处理,而不仅仅是 HTTP 状态码。

价格按输出秒数计费,列在 pricing 页面;由于片段长度跟随你的音频,成本随音频时长变化。

相关指南

常见问题

我可以用文本而不是音频文件来驱动 omnihuman-1.5 吗? 不可以。audio_url 是必填的,模型会对该音频进行口型同步。若需要从脚本到视频的流程,请先合成语音(任意 TTS),或使用像 heygen-avatar-v 这样的文本驱动数字人,然后将音频 URL 传到这里。

输出视频有多长? 跟随你的音频片段——没有 duration 参数。12 秒的语音轨道大约会生成 12 秒的视频。

什么样的图像效果最好? 一张光线清晰、正面的单人人像,位于公开 URL。合影或人脸严重遮挡会导致口型同步效果较差。

720p 还是 1080p? 两者都可用于 resolution。迭代时从 720p 开始;最终渲染时切换到 1080p。更高分辨率每秒成本更高——请参阅 pricing。

我的任务立即返回 status: "fail"。为什么? 几乎总是服务端无法获取某个输入 URL。请确认 image_url 和 audio_url 可公开访问(在无痕窗口中打开它们)且未过期。data.error 信息可帮助缩小范围。

我需要轮询,还是可以用 webhook? 两者皆可。简单脚本可使用 GET /v1/tasks/{id} 轮询;生产环境可注册 callback.url 并将 when 设为 "final",这样就不必保持轮询循环。

立即开始构建持久 AI 产物

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

阅读 API 文档