手把手教你用JAVA实现“声音复刻”功能(复刻你的声音)标贝科技

手把手教你用JAVA实现“声音复刻”功能(复刻你的声音)标贝科技

前言

什么是声音复刻?
使用少量的用户声音,短时间内快速为用户量身打造个人定制音色

一、内容太长不愿意看,直接使用系列

声音复刻分为两步
(1)定制模型
参数要求:
支持音频文件的编码格式及文件名的后缀: wav,pcm
支持音频文件的采样率: 16000Hz
支持音频文件的位深:16bits
支持的语言:中文
音频有效时长:不小于3分钟
音频的音质、音量均对模型效果有直接影响,请保证音频的录音环境相对安静、音频人声音量不能太小。
(2)定制声音合成
参数要求:
支持设置合成音频的格式: pcm,wav,mp3,alaw,ulaw
支持设置合成音频的采样率: 16000Hz
支持设置音量、语速、语调
支持语言: 中文(zh)
支持声音模型类型:普通音质、精品音质
确认无误后,直接执行 2.2获取权限+2.3.6完整代码示例

二、用JAVA调用标贝科技“声音复刻”接口使用流程

2.1.环境准备

java

2.2.获取权限

2.1.1.登录

地址:https://ai.data-baker.com/#/?source=qaz123
(注:填写邀请码hi25d7,每日免费调用量还可以翻倍)
​​​​​​在这里插入图片描述
在这里插入图片描述

点击上方地址登录,支持短信、密码、微信三种登录方式。

在这里插入图片描述

2.1.2.创建应用

登录后,点击创建应用,填写相关信息(未实名认证只能创建一个应用)
(注:实名认证后可获得创建多个应用的权限)
在这里插入图片描述

进入应用,其中包含的技术产品有:语音识别、语音合成、声音复刻、声音转换
页面中功能主要包括:服务用量管理、购买服务量管理、开发者文档、授权管理、套餐管理

在这里插入图片描述

2.1.3.获取token

点击声音复刻--->授权管理--->显示--->获取APISecret--->(获取访问令牌token
在这里插入图片描述

2.3.代码实现

2.3.1.获取token

/**
     * 授权:需要在开放平台获取【https://ai.data-baker.com/#/?source=qaz123】
     */
    private static final String clientId = "输入你的clientid";
    private static final String clientSecret = "输入你的clientsecret";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";
	public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        // request 默认是get请求
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                // 解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }

2.3.2.定制模型--提交复刻任务
参数说明:
access_token:鉴权token
originFiles:音频文件集合
mobile:手机号(用于模型训练之后短信提醒)
notifyUrl:回调url

private static void doSoundReproduction(String accessToken, List<File> originFiles, String mobile, String notifyUrl) {
        //创建连接
        OkHttpClient client = new OkHttpClient();
        //构建requestBody,传入参数
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (File file : originFiles) {
            RequestBody body = RequestBody.create(file, MediaType.parse("multipart/form-data"));
            String filename = file.getName();
            requestBody.addFormDataPart("originFiles", filename, body);
        }
        requestBody.addFormDataPart("access_token", accessToken);
        requestBody.addFormDataPart("mobile", mobile);
        requestBody.addFormDataPart("notifyUrl", notifyUrl);

        //构造request
        Request request = new Request.Builder()
                .url(soundReproductionUrl)
                .method("POST", requestBody.build())
                .build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println("调用成功,返回结果:" + response.body().string());
            } else {
                System.out.println("调用失败,返回结果:" + response.body().string());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.3.3.定制模型-回调代码

@ApiOperation(value = "测试用回调接口", notes = "该链接由参数notifyUrl设置,如果链接无法访问,将无法接收到回调的push信息。")
@PostMapping("/notify")
public void synthesisNotify(HttpServletRequest request, HttpServletResponse response) {
    String resXml = "";
    InputStream inStream;
    try {
        inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        // 获取声音复刻api调用notifyUrl的返回信息
        String result = new String(outSteam.toByteArray(), "utf-8");
        log.info("dataBaker:声音复刻api返回结果 ----result---- =" + result);
        // 关闭流
        outSteam.close();
        inStream.close();
        // String转换为json对象,然后业务处理
        JSONObject jsonObject = JSON.parseObject(result);
        //该参数表示模型id
        String modelId = jsonObject == null ? "" : jsonObject.getString("modelId");
        //该参数表示模型当前状态:可能的值为success/fail, 其中,success=训练成功 fail=训练失败
        String modelStatus = jsonObject == null ? "" : jsonObject.getString("modelStatus");
        //该参数表示原因(文案可能会有变动),成功时为空字符串,失败时为失败原因说明
        String reason = jsonObject == null ? "" : jsonObject.getString("reason");
        //具体业务处理,例如尝试tts调用等(可先返回结果,然后异步去完成业务逻辑)
        //todo
        //根据情况,向结果中赋值:正常情况下,选择下面的resSuccess;如果选择resFail,将会视为推送失败,标贝服务端将重新推送一次相同的内容
        //     * 返回成功xml
        //     */
        //    String resSuccess = "<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>";
        //    /**
        //     * 返回失败xml
        //     */
        //    String resFail = "<xml><return_code>FAIL</return_code><return_msg>报文为空</return_msg></xml>";resXml = Constant.resSuccess;
        //记录日志
        log.info("dataBaker:声音复刻api回调返回模型  {}  的状态为:--->{}", modelId , modelStatus);
        } catch (Exception e) {
            log.error("dataBaker:声音复刻api回调异常:", e);
        } finally {
            try {
                // 处理业务完毕
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (IOException e) {
                log.error("dataBaker:声音复刻api回调异常:out:", e);
            }
        }
    }

2.3.4.定制声音合成-文本格式转换及地址参数拼接
参数说明:
voiceName:定制模型时返回的model_id
originText:合成文本
audioType:音频格式
speed:语速
volume:音量
filePath:输出文件路径

/**
     * 请求并获取音频流保存至本地文件:这里filePath为全路径
     *
     * @param url
     * @param filePath
     * @throws IOException
     */
    public static void fetchTtsResponse(String url, String filePath) throws IOException {
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        Request request = new Request.Builder().url(url).build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                if (response.body() != null
                        && response.body().contentType().toString().startsWith("audio")) {
                    //写入文件
                    File targetFile = new File(filePath);
                    Files.write(targetFile.toPath(), response.body().bytes());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.3.5.定制声音合成-调用语音合成接口合成音频

public static void doSynthesis(String accessToken, String voiceName, String originText, Integer audioType, Double speed, Double volume, String filePath) {
        //在非浏览器上操作,需要把合成文本转化为utf-8格式
        try {
            originText = URLEncoder.encode(originText, "utf-8");
            String synthesisUrl = String.format(ttsUrl, accessToken, audioType, voiceName, speed, volume, originText);
            fetchTtsResponse(synthesisUrl, filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.3.6.完整代码事例
定制模型完整代码

package com.databaker.web.tts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;


/**
 * 声音复刻RESTFUL API接口调用示例
 * 附:声音复刻RESTFUL API文档 【https://www.data-baker.com/specs/file/reprint_api_restful】
 *
 * 注意:仅作为demo示例,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成
 *
 * @author data-baker
 */
public class TtsSoundReproductionApiDemo {

    /**
     * 授权:需要在开放平台获取【https://ai.data-baker.com/】
     */
    private static final String clientId = "YOUR_CLIENT_ID";
    private static final String clientSecret = "YOUR_CLIENT_SECRET";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";
    /**
     * 声音复刻API地址
     */
    public static String soundReproductionUrl = "https://openapi.data-baker.com/gramophone/v1/submit";

    /**
     * 音频列表,需满足一定条件:
     * 1.格式为pcm或wav
     * 2.采样率为16000hz,位深为16bit,单声道
     * 3.有效时长最好不小于3分钟(接口实际是以识别出的字数作为判定标准)
     */
    public static List<File> originFiles = new ArrayList<>();

    public static void main(String[] args) {
        String accessToken = getAccessToken();
        if (StringUtils.isNotEmpty(accessToken)) {
            doSoundReproduction(accessToken, originFiles, "mobile", "https://openapi.data-baker.com/gramophone/v1/api/notify");
        }
    }

    /**
     * 提交复刻任务
     *
     * 开发者需开发一个回调接口,接口地址作为参数notifyUrl,用来接收模型训练的结果,具体写法可参考接口文档【https://www.data-baker.com/specs/file/reprint_api_restful】中的回调部分
     */
    private static void doSoundReproduction(String accessToken, List<File> originFiles, String mobile, String notifyUrl) {
        //创建连接
        OkHttpClient client = new OkHttpClient();
        //构建requestBody,传入参数
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (File file : originFiles) {
            RequestBody body = RequestBody.create(file, MediaType.parse("multipart/form-data"));
            String filename = file.getName();
            requestBody.addFormDataPart("originFiles", filename, body);
        }
        requestBody.addFormDataPart("access_token", accessToken);
        requestBody.addFormDataPart("mobile", mobile);
        requestBody.addFormDataPart("notifyUrl", notifyUrl);

        //构造request
        Request request = new Request.Builder()
                .url(soundReproductionUrl)
                .method("POST", requestBody.build())
                .build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println("调用成功,返回结果:" + response.body().string());
            } else {
                System.out.println("调用失败,返回结果:" + response.body().string());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                //解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }
}

定制声音合成完整代码

package com.databaker.web.tts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;

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

/**
 * 语音合成(个性化音色)RESTFUL API接口调用示例
 * 附:语音合成(个性化音色)RESTFUL API文档 【https://www.data-baker.com/specs/file/reprint_api_compose】
 *
 * 注意:仅作为demo示例,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成
 *
 * @author data-baker
 */
public class TtsPersonalRestApiDemo {
    /**
     * 授权:需要在开放平台获取【https://ai.data-baker.com/】
     */
    private static final String clientId = "YOUR_CLIENT_ID";
    private static final String clientSecret = "YOUR_CLIENT_SECRET";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";
    /**
     * 合成使用的地址信息,rate、language等参数在本demo固定,开发者如需调整,参考https://www.data-baker.com/specs/file/reprint_api_compose
     */
    public static String ttsUrl = "https://openapi.data-baker.com/tts_personal?access_token=%s&domain=1&audiotype=%s&language=zh&voice_name=%s&speed=%s&volume=%s&text=%s";

    /**
     * 仅作为demo示例
     * 失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成
     **/
    public static void main(String[] args) {
        String accessToken = getAccessToken();
        if (StringUtils.isNotEmpty(accessToken)) {
            //此处voiceName应传入已成功完成复刻过程的modelId(示例:YOUR_MODEL_ID = 5c97a06ce40cf69e33d2d05c25d4807f9f657)
            doSynthesis(accessToken, "YOUR_MODEL_ID", "测试文本", 6, 5.0, 5.0, "/home/tts/test.wav");
        }
    }

    public static void doSynthesis(String accessToken, String voiceName, String originText, Integer audioType, Double speed, Double volume, String filePath) {
        //在非浏览器上操作,需要把合成文本转化为utf-8格式
        try {
            originText = URLEncoder.encode(originText, "utf-8");
            String synthesisUrl = String.format(ttsUrl, accessToken, audioType, voiceName, speed, volume, originText);
            fetchTtsResponse(synthesisUrl, filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 请求并获取音频流保存至本地文件:这里filePath为全路径
     *
     * @param url
     * @param filePath
     * @throws IOException
     */
    public static void fetchTtsResponse(String url, String filePath) throws IOException {
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        Request request = new Request.Builder().url(url).build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                if (response.body() != null
                        && response.body().contentType().toString().startsWith("audio")) {
                    //写入文件
                    File targetFile = new File(filePath);
                    Files.write(targetFile.toPath(), response.body().bytes());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                //解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }
}

地址:https://ai.data-baker.com/#/?source=qaz123
(注:填写邀请码hi25d7,每日免费调用量还可以翻倍)
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/5fc12c005cbf468d849d22abd707d64c.png

posted @ 2021-12-28 17:06  DataBaker  阅读(1388)  评论(0)    收藏  举报