博 客 - 正文

数字人V3接口开发教程

来源:创客API 分类:代码示例 SUPERADMIN 阅读(88)

数字人 V3 合成 API 接入教程

在线效果体验:https://ai.hihookeji.com

提交接口:https://api.hihookeji.com/api/humanmetav3/index

查询接口:https://api.hihookeji.com/api/queryclonehumanv3/index

返回格式:application/json

请求方式:HTTP POST


一、接口概述

本接口将 原视频 与驱动 音频(wav) 合成数字人开口视频。提交后可通过 notify_url 回调拿结果,也可用 查询接口taskid 轮询状态与成果地址。

项目说明
提交接口https://api.hihookeji.com/api/humanmetav3/index
查询接口https://api.hihookeji.com/api/queryclonehumanv3/index
认证方式请求体字段 key(你的 API 密钥,与业务参数一并提交)
Content-Typeapplication/json(推荐)或 application/x-www-form-urlencoded
提交业务判断提交响应以 code 为准:示例成功为 1,失败常见为 500
查询业务判断查询成功时 code200
计费1 元 / 60 秒,按秒计费

二、请求参数

2.1 提交合成(humanmetav3)

参数名类型必填描述示例
keystringAPI 密钥,放在请求体中与其它参数一起提交你的密钥
video_urlstring原视频链接(公网可访问),无需训练,直接传入即可驱动https://abc.com/video.mp4
audio_urlstring驱动音频地址,须公网可访问,wav 格式,建议 URL 以 .wav 结尾https://abc.com/audio.wav
notify_urlstring合成结果通知地址(需公网可达)见下方「回调测试」
video_namestring视频名称测试视频

回调测试:联调异步回调时,建议先打开 https://webhook.site/ 获取自己的唯一 URL,将该地址填入 notify_url。提交任务后可在网页上直接查看回调字段与成果链接,无需先部署自己的回调服务。

2.2 查询结果(queryclonehumanv3)

参数名类型必填描述示例
keystringAPI 密钥,放在请求体中与其它参数一起提交你的密钥
taskidstring任务 ID;若查训练结果则传 mode_id374
tasktypestringhuamanclonev3:查询合成结果;huamanclonev1:V1 查询huamanclonev3

tasktype 取值请按接口约定原样传递(含拼写 huamanclonev3 / huamanclonev1)。新接入合成任务一般用 huamanclonev3 + 提交返回的 data.taskid

合成不会马上完成:提交后请 每隔 60 秒 主动调一次本查询接口,直到 status3(成功)或 4(失败),不要提交后立刻只查一次。


三、更新说明

2025-12-03

  1. 新增 video_url:可直接传原视频链接,无需训练

四、返回结果说明

4.1 任务提交成功

立即返回任务受理结果,合成视频通过 notify_url 回调。

字段说明
code成功时示例为 1
msg说明信息,如 ok
time时间戳
data.taskid视频任务 ID,与回调关联

{

"code": 1,

"msg": "ok",

"time": "1722863371",

"data": {

"taskid": 374

}

}

4.2 任务提交失败


{

"code": 500,

"msg": "不能为空"

}

4.3 异步回调 Notify

服务端合成完成后,向 notify_url POST 推送结果(表单字段;不是 JSON Body)。

字段说明
errcode0 成功1001 失败(与提交响应的 code 不同,回调按此处判断)
taskid视频任务 ID
target_file成果视频链接(如 https://1234.com/video.mp4),请及时下载
video_time视频时长,单位:秒
msg通知信息

本接口回调的 target_file视频 URL 字符串,不是文件流上传。收到后请尽快下载保存。

4.4 查询合成结果成功(tasktype=huamanclonev3)

查询成功时 code200

data 字段说明
taskid任务 ID
status合成状态:-1 编辑中,1 排队中,2 合成中,3 合成成功,4 合成失败
audio_url驱动音频地址
mode_id模型 ID(历史字段,新流程以 video_url 提交为主)
result_video_url成果视频地址(成功时有值)
video_time视频时长(秒)

{

"code": 200,

"msg": "任务查询成功",

"data": {

"taskid": 123456,

"status": 3,

"audio_url": "https://oml.img.vodeshop.com/uploads/voice/20250224/20250224114152f79b25015.wav",

"mode_id": 363546,

"result_video_url": "https://opendigman.oss-cn-hangzhou.aliyuncs.com/aivideo/202502/24/20250224_1150261740369026196629.mp4",

"video_time": 11.21

}

}

status=3 时,用 data.result_video_url 下载成果视频即可。查询非即时有结果:建议 每 60 秒轮询一次,直到成功或失败。


五、接入流程建议

  1. 准备公网可访问的原视频(video_url)与驱动音频(audio_url,标准 wav,URL 建议以 .wav 结尾)。
  1. 申请 API Key,作为请求体字段 key 与其它参数一起提交。
  1. 填入 notify_url;联调可用 webhook.site 唯一地址。
  1. 调用提交接口,成功后记录 data.taskid
  1. 结果获取二选一或并用:
  • 等待 notify_url 回调(errcode=0 后下载 target_file);
  • 或主动轮询查询接口:taskid + tasktype=huamanclonev3每隔 60 秒查一次,直到 status=3 再下载 result_video_urlstatus=4 则失败结束)。
  1. 成果链接请及时下载落盘。

六、Python 完整代码

依赖:requestspip install requests


# -*- coding: utf-8 -*-

"""

数字人 V3 合成 API - Python 完整示例

接口: https://api.hihookeji.com/api/humanmetav3/index

"""

import json

import os

import time

import requests

SUBMIT_URL = "https://api.hihookeji.com/api/humanmetav3/index"

QUERY_URL = "https://api.hihookeji.com/api/queryclonehumanv3/index"

API_KEY = "你的密钥"  # 替换为真实密钥

def create_human_video(

video_url,

audio_url,

notify_url,

video_name="测试视频",

timeout=60,

):

"""提交数字人合成任务(异步)。"""

payload = {

"key": API_KEY,

"video_url": video_url,

"audio_url": audio_url,

"notify_url": notify_url,

"video_name": video_name,

}

resp = requests.post(

SUBMIT_URL,

json=payload,

headers={"Content-Type": "application/json"},

timeout=timeout,

)

resp.raise_for_status()

return resp.json()

def query_human_video(taskid, tasktype="huamanclonev3", timeout=60):

"""

查询任务结果。

tasktype: huamanclonev3=查询合成结果;huamanclonev1=V1 查询

"""

payload = {

"key": API_KEY,

"taskid": str(taskid),

"tasktype": tasktype,

}

resp = requests.post(

QUERY_URL,

json=payload,

headers={"Content-Type": "application/json"},

timeout=timeout,

)

resp.raise_for_status()

return resp.json()

def wait_human_video(taskid, interval_sec=60, max_tries=60, tasktype="huamanclonev3"):

"""

每隔 interval_sec 秒查询一次,直到成功(status=3)、失败(status=4) 或超过次数。

合成不会马上有结果,默认间隔 60 秒。

"""

last = None

for i in range(max_tries):

last = query_human_video(taskid, tasktype=tasktype)

data = last.get("data") or {}

status = data.get("status")

print(f"第 {i + 1} 次查询 status={status}:", json.dumps(last, ensure_ascii=False))

if int(last.get("code") or 0) == 200 and status is not None:

status = int(status)

if status == 3:

return last

if status == 4:

raise RuntimeError(f"合成失败: {last.get('msg')}")

time.sleep(interval_sec)

raise TimeoutError(f"超过轮询次数仍未完成,最后结果: {last}")

def download_result_video(video_url, save_path):

"""根据回调 target_file 或查询 result_video_url 下载成果视频。"""

r = requests.get(video_url, timeout=120)

r.raise_for_status()

parent = os.path.dirname(save_path)

if parent:

os.makedirs(parent, exist_ok=True)

with open(save_path, "wb") as f:

f.write(r.content)

return save_path

# ---------------------------------------------------------------------------

# Flask 异步回调接收示例(可选)

# 安装: pip install flask

# ---------------------------------------------------------------------------

def create_notify_app(save_dir="./callback_video"):

from flask import Flask, request, jsonify

app = Flask(__name__)

os.makedirs(save_dir, exist_ok=True)

@app.route("/Notify", methods=["POST"])

def notify():

# 回调为表单字段,不是 JSON Body

taskid = request.form.get("taskid")

msg = request.form.get("msg")

errcode = request.form.get("errcode")  # 成功 0,失败 1001

target_file = request.form.get("target_file") or ""

video_time = request.form.get("video_time")

if str(errcode) == "0" and target_file:

path = os.path.join(save_dir, f"{taskid}.mp4")

download_result_video(target_file, path)

return jsonify({

"ok": True,

"taskid": taskid,

"saved": path,

"video_time": video_time,

"errcode": errcode,

})

return jsonify({

"ok": False,

"taskid": taskid,

"msg": msg,

"errcode": errcode,

})

return app

if __name__ == "__main__":

result = create_human_video(

video_url="https://abc.com/video.mp4",

audio_url="https://abc.com/audio.wav",

notify_url="https://webhook.site/你的唯一ID",

video_name="测试视频",

)

print("任务提交:", json.dumps(result, ensure_ascii=False, indent=2))

# 成功时 code==1,记录 data.taskid

taskid = (result.get("data") or {}).get("taskid")

if taskid:

# 不会马上有结果:默认每 60 秒查一次,直到 status=3/4

query = wait_human_video(taskid, interval_sec=60)

url = (query.get("data") or {}).get("result_video_url")

if url:

path = download_result_video(url, f"./output/{taskid}.mp4")

print("已下载:", path)

# ---------- 启动回调服务(需要时取消注释)----------

# app = create_notify_app()

# app.run(host="0.0.0.0", port=8080)

八、Java 完整代码

依赖:JDK 8+,使用内置 HttpURLConnection,无需第三方库。


import java.io.*;

import java.net.HttpURLConnection;

import java.net.URL;

import java.nio.charset.StandardCharsets;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

/**

* 数字人 V3 合成 API - Java 完整示例

* 接口: https://api.hihookeji.com/api/humanmetav3/index

*/

public class HumanMetaV3Demo {

private static final String SUBMIT_URL = "https://api.hihookeji.com/api/humanmetav3/index";

private static final String QUERY_URL = "https://api.hihookeji.com/api/queryclonehumanv3/index";

private static final String API_KEY = "你的密钥"; // 替换为真实密钥

public static class HumanRequest {

public String videoUrl;

public String audioUrl;

public String notifyUrl;

public String videoName = "测试视频";

}

public static String createHumanVideo(HumanRequest req, int timeoutMs) throws IOException {

return postJson(SUBMIT_URL, toSubmitJson(req), timeoutMs);

}

/** tasktype: huamanclonev3=合成结果;huamanclonev1=V1 查询 */

public static String queryHumanVideo(String taskid, String tasktype, int timeoutMs) throws IOException {

StringBuilder sb = new StringBuilder();

sb.append("{");

sb.append(""key":").append(quote(API_KEY)).append(",");

sb.append(""taskid":").append(quote(taskid)).append(",");

sb.append(""tasktype":").append(quote(tasktype));

sb.append("}");

return postJson(QUERY_URL, sb.toString(), timeoutMs);

}

private static String postJson(String apiUrl, String json, int timeoutMs) throws IOException {

URL url = new URL(apiUrl);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");

conn.setConnectTimeout(15000);

conn.setReadTimeout(timeoutMs);

conn.setDoOutput(true);

conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");

conn.setRequestProperty("Accept", "application/json");

byte[] body = json.getBytes(StandardCharsets.UTF_8);

conn.setRequestProperty("Content-Length", String.valueOf(body.length));

try (OutputStream os = conn.getOutputStream()) {

os.write(body);

}

int httpCode = conn.getResponseCode();

InputStream is = (httpCode >= 200 && httpCode < 300)

? conn.getInputStream()

: conn.getErrorStream();

String resp = readFully(is);

conn.disconnect();

return resp;

}

public static Path downloadResultVideo(String videoUrl, String savePath) throws IOException {

URL url = new URL(videoUrl);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setConnectTimeout(15000);

conn.setReadTimeout(120000);

conn.setRequestMethod("GET");

try (InputStream is = conn.getInputStream()) {

byte[] bytes = readBytes(is);

Path path = Paths.get(savePath);

Path parent = path.getParent();

if (parent != null && !Files.exists(parent)) {

Files.createDirectories(parent);

}

Files.write(path, bytes);

return path;

} finally {

conn.disconnect();

}

}

private static String toSubmitJson(HumanRequest r) {

StringBuilder sb = new StringBuilder();

sb.append("{");

sb.append(""key":").append(quote(API_KEY)).append(",");

sb.append(""video_url":").append(quote(r.videoUrl)).append(",");

sb.append(""audio_url":").append(quote(r.audioUrl)).append(",");

sb.append(""notify_url":").append(quote(r.notifyUrl)).append(",");

sb.append(""video_name":").append(quote(r.videoName));

sb.append("}");

return sb.toString();

}

private static String quote(String s) {

if (s == null) {

return "null";

}

String escaped = s

.replace("\", "\\")

.replace(""", "\"")

.replace("n", "\n")

.replace("r", "\r")

.replace("t", "\t");

return """ + escaped + """;

}

private static String readFully(InputStream is) throws IOException {

return new String(readBytes(is), StandardCharsets.UTF_8);

}

private static byte[] readBytes(InputStream is) throws IOException {

if (is == null) {

return new byte[0];

}

ByteArrayOutputStream bos = new ByteArrayOutputStream();

byte[] buf = new byte[4096];

int n;

while ((n = is.read(buf)) != -1) {

bos.write(buf, 0, n);

}

return bos.toByteArray();

}

/*

* 回调 Servlet 伪代码:

* @WebServlet("/Notify")

* 表单字段: errcode(成功0/失败1001), taskid, target_file(视频URL), video_time, msg

* 成功时下载 target_file 保存为本地 mp4

*/

public static void main(String[] args) throws Exception {

HumanRequest req = new HumanRequest();

req.videoUrl = "https://abc.com/video.mp4";

req.audioUrl = "https://abc.com/audio.wav";

req.notifyUrl = "https://webhook.site/你的唯一ID";

req.videoName = "测试视频";

String resp = createHumanVideo(req, 60000);

System.out.println("任务提交: " + resp);

// 成功时 code==1,记录 data.taskid

// 合成非即时:每隔 60 秒调用 queryHumanVideo(taskid, "huamanclonev3", 60000)

// 直到 status==3 取 result_video_url 下载;status==4 失败结束

}

}

九、常见问题

问题处理建议
仍传 mode_id已废除;请改用 video_url 直传原视频,无需训练
音频格式不对audio_url 必须是公网可访问的 wav;失败可用 ffmpeg 转码:ffmpeg -i 输入文件 -acodec pcm_s16le -ar 16000 输出.wav
音频 / 视频链接后缀不对音频 URL 建议以 .wav 结尾;视频建议 .mp4 结尾。OSS 带鉴权的长链接不以该后缀结尾时易失败,需换成后缀正确的直链或转存后再提交
驱动音频无法访问确认 audio_urlvideo_url 公网可下载,且无防盗链拦截服务端拉取
只看 HTTP 200提交接口成功示例为 code:1;查询接口成功为 code:200,勿混用
查询一直排队/合成中提交后不会马上有结果:建议 每 60 秒查一次status1 排队,2 合成中,3 成功,4 失败
提交后立刻查询无视频正常现象;请按 60 秒间隔继续轮询,勿只查一次就判定失败
tasktype 填错查合成结果必须传 huamanclonev3(按接口拼写原样传)
异步收不到回调确认 notify_url 公网可达;也可用查询接口轮询;联调可用 webhook.site
回调当成 JSON 解析失败回调是表单 POST,用 form/$_POST 取值,不要按 JSON Body 解析
回调成功却判失败回调成功 errcode0,失败为 1001
成果链接失效回调 target_file 或查询 result_video_url,收到后及时下载落盘
计费疑问当前 1 元 / 60 秒,按秒计费

十、快速对照

项目说明
提交.../humanmetav3/indexkey / video_url / audio_url / notify_url
提交响应code:1 + data.taskid
查询.../queryclonehumanv3/indexkey / taskid / tasktype=huamanclonev3
轮询非即时结果,建议 每 60 秒 查一次,直到 status=3/4
查询成功code:200status=3 时取 result_video_url
回调成果notify_urlerrcode=0 + target_file(视频 URL)

数据驱动未来

立即注册

客服微信

请打开手机微信,扫一扫联系我们

返回顶部