You need to enable JavaScript to run this app.
导航

数字分身&声音复刻训练API接口文档

最近更新时间2023.09.25 10:44:33

首次发布时间2023.08.11 17:43:01

制作分身

制作一个分身形象的完整流程如下:
step1:上传制作形象所需的视频素材
step2:视频素材上传完成后,调用触发形象制作接口,开始形象制作
step3:调用分身形象制作信息查询接口,查询形象制作状态

说明:
1、完整上传一个视频调用接口流程如下:创建分片上传任务--> 顺序上传文件分片 --> 完成文件分片上传
2、conf_name字段是形象的唯一标识,由客户自己定义,后续使用sta等服务时,需要传递该值来表明调用哪个形象 格式要求:允许大小写字母数字以及'-'
3、input_resource字段为必传字段,用于表明数据来源,建议填写公司名称

分身形象制作需要提供如下视频素材:

  • 训练视频:允许格式 1080p/4K mp4/mov

针对在控制台下单的数字人资产,在调用训练接口时:

  • 数字分身:形象id填入conf_name
  • 声音复刻:声音id填入voice_type

1、创建分片上传任务 POST

path:/init_part_upload
参数:json

{
    "conf_name": "LiuXuan",    //string 必传 用户上传形象调用conf_name,格式要求:允许大小写字母数字以及'-' 
    "role_show_name": "刘璇",   //string 必传 用户上传形象展示中文名
    "type": 1,   //int 必传  视频类型1:训练视频 2:模版视频 3:审核视频
    "input_resource": "",  //string 必传 视频上传来源,建议填写公司名称
    "appid": "xxxx",  //string 必传 appid
    "file_suffix": "mp4" //string 必传 视频格式尾缀 mp4或mov
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": {
        "upload_id": "48501f0206918d1b5db63714" // 返回upload_id,用于标识此次分片上传任务
    }
}

2、上传文件分片 POST

说明:建议分片大小为10M,最后一片不足5M的与前一分片合并上传
path:/video_part_upload
参数:json

{
        "conf_name": conf_name,  // string 必传 用户上传形象调用conf_name,格式要求:允许大小写字母数字以及'-'
        "type": video_type,   //int 必传  视频类型1:训练视频 2:模版视频 3:审核视频
        "upload_id": upload_id, //string 必传  init_part_upload接口返回的upload_id
        "file_suffix": "mp4", //string 必传 视频格式尾缀 mp4或mov
        "part_num": 1,  //int 必传  分片顺序:1,2,3,4... 要求第一个分片必须从1开始
        "content": "base64", //string 必传 分片内容,base64字符串
        "appid": "xxxx",  //string 必传 appid
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": "video part upload success"
}

3、完成文件分片上传 POST

path:/video_complete_upload
参数:json

{
        "conf_name": conf_name,  // string 必传 用户上传形象调用conf_name,格式要求:允许大小写字母数字以及'-'
        "type": video_type,  //int 必传 视频类型1:训练视频 2:模版视频 3:审核视频
        "upload_id": upload_id,  //string 必传 init_part_upload接口返回的upload_id
        "file_suffix": "mp4", //string 必传 视频格式尾缀 mp4或mov
        "appid": "xxxx",  //string 必传 appid
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": "finish video part upload successs"
}

4、触发形象制作 POST

说明:触发形象训练
path:/init_train_digime
参数:json

{
    "appid": "xxx",  //string 必传 appid
    "conf_name": "xxx",  //string 必传 用户上传形象调用conf_name,格式要求:允许大小写字母数字以及'-'
    "callback_url": "http://xxx.net/xx"    // 回调地址,POST,用于接收制作状态回调
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": "init train digime succ"
}

制作状态回调格式如下:

传递的URL地址需支持POST method

{
    "conf_name": "xxx",  //string 形象调用conf_name
    "role_pic": "https://xxx.png", //形象图
    "pre_pic": "https://xxx.png", //前景图
    "state": 2     // 2:制作成功,3:制作失败
}

5、分身形象制作信息查询 POST

说明:通过conf_name查询分身形象制作状态信息
path:/digime_training_info
参数:json

{
    "appid": "xxx",  //string appid
    "conf_name": "xxx"  //string 用户上传形象调用conf_name,格式要求:允许大小写字母数字以及'-'
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": {
        "conf_name": "xxx",  //string 形象调用conf_name
        "role_pic": "https://xxx.png", //形象图
        "pre_pic": "https://xxx.png", //前景图
        "state": 2 //制作状态 1:制作中,2:制作成功,3:制作失败
    }
}

6、接口地址

正式环境:https://openspeech.bytedance.com/virtual_human/avatar_platform/digime

7、Demo

# script/init.py
# coding=utf-8

#####################

import json
import requests
import os
import base64

UPLOAD_URL = "https://openspeech.bytedance.com/virtual_human/avatar_platform/digime"


def check_res(result):
    if result.status_code != 200:
        raise Exception(f"request code is not {result.status_code}")
    # print(result.text)
    res = result.json()
    if res.get("errMsg") != "success" or res.get("errno") != 0:
        msg = res.get("errMsg")
        raise Exception(f"request err, msg: {msg}")
    return res


def post(url, data, token):
    """封装post方法"""
    headers = {'Content-Type': 'application/json', 'Authorization': token}
    result = requests.post(url=url, headers=headers, data=json.dumps(data))
    return check_res(result)


# def post_form(url, filepath, filekey, **kwargs):
#     """封装post方法 body是format data形式"""
#     data = kwargs.get("data")
#     fl = open(filepath, 'rb')
#     files = {
#         filekey: (filepath, fl)
#     }
#     result = requests.post(url, files=files, data=data)
#     print(check_res(result))

""" 按块读取 """


def read_file_by_chunk(file, chunk_size=1024 * 1024 * 10):
    with open(file, mode='rb') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                return
            yield chunk


def part_upload_file(file_path, conf_name, role_show_name, video_type, input_resource, app_id, token):
    init_data = {
        "conf_name": conf_name,
        "type": video_type,
        "role_show_name": role_show_name,
        "input_resource": input_resource,
        "appid": app_id,
        "file_suffix": file_path[-3:],
    }
    ret = post(UPLOAD_URL + "/init_part_upload", init_data, token)
    upload_id = ret["data"]
    print("upload_id is:", upload_id)

    upload_data = {
        "conf_name": conf_name,
        "type": video_type,
        "upload_id": upload_id,
        "appid": app_id,
        "file_suffix": file_path[-3:],
    }
    part_num = 1
    # 暂存前一个分片
    tmp_content_str = ""
    tmp_bytes = bytes()
    final_deal = True
    chunks = read_file_by_chunk(file_path)
    for chunk in chunks:
        # print("chunk size is:", len(bytes(chunk)))
        if part_num == 1:
            content = base64.b64encode(bytes(chunk))
            tmp_content_str = content.decode()
            tmp_bytes = bytes(chunk)
            part_num += 1
            continue
        if len(bytes(chunk)) >= 5242880:
            # 当前分片长度大于等于5m,上传前一个分片
            upload_data["part_num"] = part_num - 1
            upload_data["content"] = tmp_content_str
            print("upload part:", part_num - 1)
            ret = post(UPLOAD_URL + "/video_part_upload", upload_data, token)
            content = base64.b64encode(bytes(chunk))
            tmp_content_str = content.decode()
            tmp_bytes = bytes(chunk)
        else:
            # print("deal with last partiton merged")
            # 当前分片长度小于5m,与前一个分片合并上传
            # print("tmp_bytes size is:%d, chunk size is:%d", len(tmp_bytes), len(bytes(chunk)))
            content = base64.b64encode(tmp_bytes + bytes(chunk))
            content_str = content.decode()
            upload_data["part_num"] = part_num - 1
            upload_data["content"] = content_str
            print("upload part:", part_num - 1)
            ret = post(UPLOAD_URL + "/video_part_upload", upload_data, token)
            final_deal = False
        part_num += 1
    if final_deal:
        # print("deal with last partiton")
        upload_data["part_num"] = part_num - 1
        upload_data["content"] = tmp_content_str
        print("upload part:", part_num - 1)
        ret = post(UPLOAD_URL + "/video_part_upload", upload_data, token)

    complete_data = {
        "conf_name": conf_name,
        "type": video_type,
        "upload_id": upload_id,
        "appid": app_id,
        "file_suffix": file_path[-3:]
    }
    ret = post(UPLOAD_URL + "/video_complete_upload", complete_data, token)


if __name__ == "__main__":
    print("########begin part upload############")
    part_upload_file("2.mp4", "conf_name", "role_show_name", 1, "input_resource", "appid", "token")


制作音色

制作一个音色的完整流程如下:
step1:上传制作音色所需音频素材压缩包(多条音频文件放到一个文件夹下压缩),格式要求zip或者tar

说明:
1、完整上传一个音频素材压缩包调用接口流程如下:创建分片上传任务--> 顺序上传文件分片 --> 完成文件分片上传
2、input_resource字段为必传字段,用于表明数据来源,建议填写公司名称

1、创建分片上传任务 POST

path:/init_part_upload
参数:json

{
    "conf_name": "",    //string 可选 音色对应分身形象conf_name
    "type": 11,   //int 必传  数据类型 11:音频压缩包数据
    "input_resource": "",  //string 必传 视频上传来源,建议填写公司名称
    "appid": "xxxx",  //string 必传 appid
    "file_suffix": "zip", //string 必传 压缩格式尾缀 zip或tar
    "tts_type": "xxx" //tts_model_v1 30min复刻 tts_model_v2 10min复刻
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": {
        "upload_id": "48501f0206918d1b5db63714" // 返回upload_id,用于标识此次分片上传任务
    }
}

2、上传文件分片 POST

说明:建议分片大小为10M,最后一片不足5M的与前一分片合并上传
path:/video_part_upload
参数:json

{
        "type": 11,   //int 必传  数据类型 11:音频压缩包数据
        "upload_id": upload_id, //string 必传  init_part_upload接口返回的upload_id
        "file_suffix": "zip" //string 必传 压缩格式尾缀 zip或tar
        "part_num": 1,  //int 必传  分片顺序:1,2,3,4... 要求第一个分片必须从1开始
        "content": "base64", //string 必传 分片内容,base64字符串
        "appid": "xxxx",  //string 必传 appid
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": "video part upload success"
}

3、完成文件分片上传 POST

path:/video_complete_upload
参数:json

{
        "type": 11,   //int 必传  数据类型 11:音频压缩包数据
        "upload_id": upload_id,  //string 必传 init_part_upload接口返回的upload_id
        "file_suffix": "zip" //string 必传 压缩格式尾缀 zip或tar
        "appid": "xxxx",  //string 必传 appid
}

Headers:

headers = {'Content-Type': 'application/json', 'Authorization': token}

返回:

{
    "errno": 0,
    "errMsg": "success",
    "data": "finish video part upload successs"
}