图片训练数字人接入指南

更新时间:
复制为 MD 格式

文档详细描述了通过API创建图片训练数字人全流程,包括素材上传、任务创建、状态轮询及结果确认。

重要

图片训练数字人可用于实时对话和播报视频合成,不可用于直播。

操作流程

  1. 使用获取上传凭证API获取图片素材上传凭证并上传图片素材。

  2. 通过创建图片训练数字人API设置变量值,提交图片训练数字人创建任务。

  3. 通过查询图片训练数字人状态API轮询数字人训练状态,获取训练结果。

  4. 针对待结果确认状态的数字人,通过结果确认API进行结果确认。

1 上传图片素材

  1. 使用获取上传凭证API获取素材上传凭证。

  2. 上传图片素材文件,图片素材文件要求如下:

    1. 格式: jpg、jpeg、png。

    2. 分辨率:最小分辨率:400px,最大分辨率:7000px。

    3. 文件大小:不超过10M。

    4. 宽高比:9:16。

1.1 获取素材上传凭证

private static GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData upload(Client client, String type, File file) throws Exception {
    //获取上传凭证
    GetUploadPolicyRequest getUploadPolicyRequest = new GetUploadPolicyRequest();
    getUploadPolicyRequest.setType("INPUT_TRAIN_PIC");
    GetUploadPolicyResponse uploadPolicy = client.getUploadPolicy(getUploadPolicyRequest);
    GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData data = uploadPolicy.getBody().getData();
    System.out.println("获取上传凭证:" + JSON.toJSONString(data));
    return data;
}

1.2 上传训练图片素材

private static void uploadFile(GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData data, File file) throws IOException {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    try {
        HttpPost uploadFile = new HttpPost("https://" + data.getOssPolicy().getHost());
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();

        ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

        // 添加OSS所需的表单字段
        builder.addTextBody("key", data.getOssKey() + "/" + file.getName(), contentType);
        builder.addTextBody("policy", data.getOssPolicy().getPolicy(), contentType);
        builder.addTextBody("OSSAccessKeyId", data.getOssPolicy().getAccessId(), contentType);
        builder.addTextBody("signature", data.getOssPolicy().getSignature(), contentType);
        // 添加文件
        builder.addBinaryBody("file", Files.newInputStream(file.toPath()), ContentType.IMAGE_PNG, file.getName());
        HttpEntity multipart = builder.build();
        uploadFile.setEntity(multipart);
        CloseableHttpResponse response = httpClient.execute(uploadFile);
        try {
            HttpEntity responseEntity = response.getEntity();
            System.out.println("Upload result: " + response.getStatusLine());
            if (responseEntity != null) {
                String responseString = EntityUtils.toString(responseEntity);
                System.out.println("Response content: " + responseString);
            }
            EntityUtils.consume(responseEntity);
        } finally {
            response.close();
        }
    } finally {
        httpClient.close();
    }
}

2 创建图片训练数字人

说明

如果图片素材存在内容安全问题,创建图片训练数字人会失败。

private static CreateTrainPicAvatarResponse createTrainPicAvatar(GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData imageData,
                                                                 File imageFile,
                                                                 ListTemplateMaterialResponse listTemplateMaterialResponse,
                                                                 Client client) throws Exception {
    CreateTrainPicAvatarRequest trainPicAvatarRequest = new CreateTrainPicAvatarRequest();
    trainPicAvatarRequest.setName("2D图片训练数字人测试");
    //设置性别
    trainPicAvatarRequest.setGender("FEMALE");// FEMALE 或 MALE
    trainPicAvatarRequest.setImageOssPath(imageData.getOssKey() + "/" + imageFile.getName());
    
    //设置业务域,
    // 取值范围:BROADCAST-播报、CHAT-对话
    // 不传值默认为 BROADCAST
    // 适用版本:1.5.4 及以上
    trainPicAvatarRequest.setBizType("BROADCAST");
    
    //设置形象背景为透明(true)或不透明(false)默认为不透明
    trainPicAvatarRequest.setTransparent(true);
    CreateTrainPicAvatarResponse trainPicAvatar = client.createTrainPicAvatar(trainPicAvatarRequest);
    System.out.println("创建图片训练数字人:" + JSON.toJSONString(trainPicAvatar.body.getData()));
    return  trainPicAvatar;
}

3 获取图片训练数字人任务状态

根据上一步获取到的数字人ID通过查询图片训练数字人的状态API轮询查询图片训练数字人任务状态。由于数字人创建需要一定的时间,所以该接口需要定时轮询调用,建议轮询间隔3s,轮询过于频繁可能会导致查询失败。查询图片训练数字人状态直到状态显示为成功或者失败,状态为待确认的时候,使用结果确认API进行结果确认,针对失败的创建任务可以根据对应的失败原因进行修改重新提交。

private static GetTrainPicAvatarStatusResponse getTrainPicAvatarStatus(Client client, 
                                                                       CreateTrainPicAvatarResponse trainPicAvatar) throws Exception {
    GetTrainPicAvatarStatusRequest getTrainPicAvatarStatusRequest = new GetTrainPicAvatarStatusRequest();
    getTrainPicAvatarStatusRequest.setAvatarId(trainPicAvatar.body.data.avatarId);
    GetTrainPicAvatarStatusResponse trainPicAvatarStatus = client.getTrainPicAvatarStatus(getTrainPicAvatarStatusRequest);
    //状态返回:训练中(TRAINING) 训练失败(TRAIN_FAILED)待结果确认(PENDING_CONFIRM) 已完成(COMPLETED)已过期 (EXPIRED)
    System.out.println("数字人状态查询:" + JSON.toJSONString(trainPicAvatarStatus.body.getData()));
    return trainPicAvatarStatus;
}

4 针对待确认状态数字人进行结果确认

  • 待确认状态 PENDING_CONFIRM

  • 结果确认 CUSTOMER_CONFIRMED

private static ConfirmTrainPicAvatarResponse confirmTrainPicAvatar(Client client,
                                          CreateTrainPicAvatarResponse trainPicAvatar) throws Exception {
    ConfirmTrainPicAvatarRequest confirmTrainPicAvatarRequest = new ConfirmTrainPicAvatarRequest();
    confirmTrainPicAvatarRequest.setAvatarId(trainPicAvatar.body.data.avatarId);
    confirmTrainPicAvatarRequest.setStatus("CUSTOMER_CONFIRMED");
    return client.confirmTrainPicAvatar(confirmTrainPicAvatarRequest);
}

图片训练数字人完整调用示例代码

引入SDK

说明

代码适用版本:1.5.4及以上。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>lingmou20250527</artifactId>
    <version>1.5.4</version>
</dependency>

示例代码

import com.alibaba.fastjson.JSON;
import com.aliyun.lingmou20250527.Client;
import com.aliyun.lingmou20250527.models.*;
import com.aliyun.teaopenapi.models.Config;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

public class Demo {

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

        Client client = Demo.getInstance();
        //1.上传图片素材
        File imageFile = new File("D:\\images\\girl.jpg");
        GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData imageData = upload(client, "INPUT_TRAIN_PIC", imageFile);

        // 2.创建图片训练数字人,如图片存在内容安全问题或人不符合形象要求会失败.
        CreateTrainPicAvatarRequest trainPicAvatarRequest = new CreateTrainPicAvatarRequest();
        trainPicAvatarRequest.setName("2D图片训练数字人测试");
        //设置性别
        trainPicAvatarRequest.setGender("FEMALE");// FEMALE 或 MALE
        trainPicAvatarRequest.setImageOssPath(imageData.getOssKey() + "/" + imageFile.getName());
        
        //设置业务域,
        // 取值范围:BROADCAST-播报、CHAT-对话
        // 不传值默认为 BROADCAST
        // 适用版本:1.5.4 及以上
        trainPicAvatarRequest.setBizType("BROADCAST");
        
        //设置形象背景为透明(true)或不透明(false)默认为不透明
        trainPicAvatarRequest.setTransparent(true);
        CreateTrainPicAvatarResponse trainPicAvatar = client.createTrainPicAvatar(trainPicAvatarRequest);
        System.out.println("创建图片训练数字人:" + JSON.toJSONString(trainPicAvatar.body.getData()));
        //返回avatarId:数字人ID,pass:是否通过,预期训练完成时间(单位秒): expectedCompletionTime 

        //4.数字人状态查询  (需要获取创建图片训练数字人返回的数字人形象id)
        GetTrainPicAvatarStatusRequest getTrainPicAvatarStatusRequest = new GetTrainPicAvatarStatusRequest();
        getTrainPicAvatarStatusRequest.setAvatarId(trainPicAvatar.body.data.avatarId);
        GetTrainPicAvatarStatusResponse trainPicAvatarStatus = client.getTrainPicAvatarStatus(getTrainPicAvatarStatusRequest);
        //状态返回:训练中(TRAINING) 训练失败(TRAIN_FAILED)待结果确认(PENDING_CONFIRM) 已完成(COMPLETED)已过期 (EXPIRED)
        System.out.println("数字人状态查询:" + JSON.toJSONString(trainPicAvatarStatus.body.getData()));

        //用户确认 (当数字人的状态为待结果确认 (PENDING_CONFIRM)
        if (trainPicAvatarStatus.body.data.status.equals("PENDING_CONFIRM")) {
            ConfirmTrainPicAvatarRequest confirmTrainPicAvatarRequest = new ConfirmTrainPicAvatarRequest();
            confirmTrainPicAvatarRequest.setAvatarId(trainPicAvatar.body.data.avatarId);
            confirmTrainPicAvatarRequest.setStatus("CUSTOMER_CONFIRMED");
            client.confirmTrainPicAvatar(confirmTrainPicAvatarRequest);
        }
    }

    private static GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData upload(Client client, String type, File file) throws Exception {
        //获取上传凭证
        GetUploadPolicyRequest getUploadPolicyRequest = new GetUploadPolicyRequest();
        getUploadPolicyRequest.setType(type);
        GetUploadPolicyResponse uploadPolicy = client.getUploadPolicy(getUploadPolicyRequest);
        GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData data = uploadPolicy.getBody().getData();
        System.out.println("获取上传凭证:" + JSON.toJSONString(data));
        // HttpClient上传文件
        uploadFile(data, file);
        return data;
    }


    private static void uploadFile(GetUploadPolicyResponseBody.GetUploadPolicyResponseBodyData data, File file) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpPost uploadFile = new HttpPost("https://" + data.getOssPolicy().getHost());
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();

            ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

            // 添加OSS所需的表单字段
            builder.addTextBody("key", data.getOssKey() + "/" + file.getName(), contentType);
            builder.addTextBody("policy", data.getOssPolicy().getPolicy(), contentType);
            builder.addTextBody("OSSAccessKeyId", data.getOssPolicy().getAccessId(), contentType);
            builder.addTextBody("signature", data.getOssPolicy().getSignature(), contentType);
            // 添加文件
            builder.addBinaryBody("file", Files.newInputStream(file.toPath()), ContentType.IMAGE_PNG, file.getName());
            HttpEntity multipart = builder.build();
            uploadFile.setEntity(multipart);
            CloseableHttpResponse response = httpClient.execute(uploadFile);
            try {
                HttpEntity responseEntity = response.getEntity();
                System.out.println("Upload result: " + response.getStatusLine());
                if (responseEntity != null) {
                    String responseString = EntityUtils.toString(responseEntity);
                    System.out.println("Response content: " + responseString);
                }
                EntityUtils.consume(responseEntity);
            } finally {
                response.close();
            }
        } finally {
            httpClient.close();
        }
    }

    public static Client getInstance() throws Exception {
        String accessKeyId = "xxx";
        String accessKeySecret = "yyy";
        String endpoint = "lingmou.cn-beijing.aliyuncs.com";
        //或者lingmou-share.cn-beijing.aliyuncs.com

        Config config = new Config();
        // noinspection AklessInspection
        config.setAccessKeyId(accessKeyId);
        // noinspection AklessInspection
        config.setAccessKeySecret(accessKeySecret);
        config.setEndpoint(endpoint);
        return new Client(config);
    }
}

形象创建错误码

DETECT_FAILED("图像检测失败"),
DETECT_NOT_PASS("图像检测不通过"),
CONTENT_RISK("您的图片涉及平台限制内容,请重新上传"),
NO_HUMAN_BODY("未检测到人脸"),
MULTI_HUMAN_BODY("请上传单个形象图片"),
INVALID_HUMAN_PROPORTION("形象在照片中比例过大/过小"),
INVALID_IMAGE_SIZE("图片大小不符合要求"),
INVALID_PERSON_VAGUE("请上传更清晰的照片"),
INVALID_BODY_ORIENTATION("请确保身体朝向正面"),
FACE_INCOMPLETE("请确保脸部完整"),
INVALID_FACE_ORIENTATION("请确保脸部朝向正面"),