讯飞文字转语音

一. 导入依赖坐标

<!-- gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

<!-- websocket -->
<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.3.6</version>
</dependency>

<!-- httpclient -->
<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.3.5</version>
</dependency>

 

二. 添加实体

package com.test.util.audioUtil;

public class AudioEntry {

    // 文件名称(服务器上的物理路径)
    private String fileName;
    // 文件来源  如:概况...
    private String source;
    // 所属地区  如:湖北省、武汉市等
    private String fileArea;
    // 文件生成的日期
    private String fileDate;
    // 状态  是否已经完全生成
    private boolean isFinish;
    
    public String getFileName() {
        return fileName;
    }

    public String getSource() {
        return source;
    }

    public String getFileArea() {
        return fileArea;
    }

    public String getFileDate() {
        return fileDate;
    }

    public boolean isFinish() {
        return isFinish;
    }


    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public void setFileArea(String fileArea) {
        this.fileArea = fileArea;
    }

    public void setFileDate(String fileDate) {
        this.fileDate = fileDate;
    }

    public void setFinish(boolean finish) {
        isFinish = finish;
    }

}

三. 编写生成语音核心代码

package com.test.util.audioUtil;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.utils.URIBuilder;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

public class AudioSocket {

    public static Gson json = new Gson();

    // 每日生成的音频文件
    public static List<AudioEntry> audioFileDataList;
    // 每次生成的音频文件
    public static AudioEntry audioItem;

    //获取今天的日期
    public static String strDate = new SimpleDateFormat("yyyy-MM-dd ").format(new Date());

    public static WebSocketClient client;

    // 文件
    public static File file;
    // 文件操作
    public static FileOutputStream os;
    // 每次合成后的音频文件
    public static List<String> audioList;
    // 每次合成后的音频文件的数量
    public static int audioListLength;
    // 需要合成音频文件的信息
    public static JsonObject frame;
    // 音频文件是否已经合成完成
    public static boolean isAudioFinish = false;

    public static String source;
    public static String fileArea;

    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").
                append("date: ").append(date).append("\n").
                append("GET ").append(url.getPath()).append(" HTTP/1.1");
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
        String sha = Base64.encodeBase64String(hexDigits);
        String authorization = String.format("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        String para1 = Base64.encodeBase64String(authorization.getBytes(charset));
        String para2 = date;
        String para3 = url.getHost();

        URIBuilder urlBuilder = new URIBuilder("https://" + url.getHost() + url.getPath());
        urlBuilder.setParameter("authorization", para1);
        urlBuilder.setParameter("date", para2);
        urlBuilder.setParameter("host", para3);
        URI uri = urlBuilder.build();

        return uri.toString();
    }

    // 获取音频文件
    public static String getAudioFile(String audioText, String apiUrl, String apiKey, String apiSecret, String appId, String pdfAudioSavePath) throws Exception {
        // 构建鉴权url
        String authUrl = getAuthUrl(apiUrl, apiKey, apiSecret);
        // 将url中的 schema http://和https://分别替换为ws:// 和 wss://
        String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
        // 存放音频的文件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String date = sdf.format(new Date());
        File file = new File(pdfAudioSavePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        String exportPath = pdfAudioSavePath + File.separator + date + ".mp3";
        AudioSocket.file = new File(exportPath);//保存为MP3文件
        if (!AudioSocket.file.exists()) {
            AudioSocket.file.createNewFile();
        }
        os = new FileOutputStream(AudioSocket.file);
        // 发送数据
        frame = new JsonObject();
        JsonObject business = new JsonObject();
        JsonObject common = new JsonObject();
        JsonObject data = new JsonObject();
        // 填充common
        common.addProperty("app_id", appId);
        // 填充business
        business.addProperty("aue", "lame");//aue参数为lame时,保存文件格式为mp3文件
        business.addProperty("sfl", 1);//当设置保存为mp3文件时,还需将sfl设置为1
        business.addProperty("tte", "UTF8");//小语种必须使用UNICODE编码
        business.addProperty("vcn", "xiaoyan");//到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200
        business.addProperty("pitch", 50);
        business.addProperty("speed", 25);
        // 填充data
        data.addProperty("status", 2);//固定位2
        try {
            data.addProperty("text", Base64.encodeBase64String(audioText.getBytes("utf8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //填充frame
        frame.add("common", common);
        frame.add("business", business);
        frame.add("data", data);
        try {
            client = new WebSocketClient(new URI(url)) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    client.send(frame.toString());
                }

                @Override
                public void onMessage(String msg) {
                    // 处理返回数据
                    AudioSocket.ResponseData resp = null;
                    try {
                        resp = json.fromJson(msg, ResponseData.class);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (resp != null) {
                        if (resp.getCode() != 0) {
                            System.out.println("error=>" + resp.getMessage() + " sid=" + resp.getSid());
                            return;
                        }
                        if (resp.getData() != null) {
                            String result = resp.getData().audio;
                            byte[] audio = Base64.decodeBase64(result);
                            try {
                                os.write(audio);
                                os.flush();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            if (resp.getData().status == 2) {
                                audioList.add(AudioSocket.file.getPath());
                                try {
                                    os.close();
                                    if (audioListLength == audioList.size()) {
                                        String mergaFile = mergeAudioFile(audioList);
                                        // audioList里面只存放合成后的文件名
                                        if (mergaFile != null && !mergaFile.equals("")) {
                                            isAudioFinish = true;
                                            audioList.clear();
                                            audioList.add(mergaFile);

                                            audioItem = new AudioEntry();
                                            audioItem.setSource(source);
                                            audioItem.setFileArea(fileArea);
                                            audioItem.setFileDate(strDate);
                                            audioItem.setFileName(mergaFile);
                                            audioItem.setFinish(true);
                                            audioFileDataList.add(audioItem);
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    //logger.info("链接已关闭");
                }

                @Override
                public void onError(Exception e) {
                    e.printStackTrace();
                    //logger.info("发生错误已关闭");
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
        }
        client.connect();
        return exportPath;
    }

    // 合并多个mp3文件
    public static String mergeAudioFile(List<String> audioFile) throws Exception {
        if (audioFile.size() > 1) {
            //取第一个文件
            File filefin = new File(audioFile.get(0));
            FileOutputStream fileOut = new FileOutputStream(filefin, true);
            File fileRead;
            FileInputStream fileInput;
            byte b[] = new byte[1024];
            int len;
            for (int i = 1; i < audioFile.size(); i++) {
                fileRead = new File(audioFile.get(i));
                fileInput = new FileInputStream(fileRead);

                while ((len = fileInput.read(b)) != -1) {
                    for (int j = 0; j < len; j++) {
                        fileOut.write(b[j]);
                    }
                }
                fileInput.close();
                //删除合并之前的文件,
                fileRead.delete();
            }
            fileOut.close();
            return audioFile.get(0);
        }
        return audioFile.get(0);
    }

    public static class ResponseData {
        private int code;
        private String message;
        private String sid;
        private Data data;

        public int getCode() {
            return code;
        }

        public String getMessage() {
            return this.message;
        }

        public String getSid() {
            return sid;
        }

        public Data getData() {
            return data;
        }
    }

    public static class Data {
        private int status;     // 标志音频是否返回结束  status=1,表示后续还有音频返回,status=2表示所有的音频已经返回
        private String audio;   // 返回的音频,base64 编码
        private String ced;     // 合成进度
    }

}

四. 编写调用生成语音入口方法

package com.test.util.audioUtil;

import java.util.ArrayList;

public class CreateAudio {

    private static final String apiUrl = "";
    private static final String apiKey = "";
    private static final String apiSecret = "";
    private static final String appId = "";
    private static final String savePath = "D:/audio";  // 生成的语音保存地址

    public static String createAudio(String content) {
        AudioSocket.audioList = new ArrayList<>();
        AudioSocket.isAudioFinish = false;
        AudioSocket.fileArea = "武汉市";
        AudioSocket.source = "语音来源";
        if (AudioSocket.audioFileDataList == null) {
            AudioSocket.audioFileDataList = new ArrayList<>();
        }

        String exportPath = "未知地址";
        // 请求讯飞在线API,合成音频文件
        try {
            // 获取需要合成音频文件的文本
            String audioTextSub;
            AudioSocket.audioListLength = (int) Math.ceil(((double) content.length()) / 2000);//获取音频文件的数量
            // 若需要合成语音的文本数据大于2000个字符
            if (content.length() > 2000) {
                // 每2000个字符进行截取
                for (int i = 0; i < AudioSocket.audioListLength; i++) {
                    // 截取到最后
                    if (i == AudioSocket.audioListLength - 1) {
                        audioTextSub = content.substring(i * 2000) + "。";
                    } else {
                        audioTextSub = content.substring(i * 2000, (i + 1) * 2000) + "。";
                    }
                    exportPath = AudioSocket.getAudioFile(audioTextSub, apiUrl, apiKey, apiSecret, appId, savePath);
                    Thread.sleep(25000); // socket回调方法,延时20秒
                }
            } else {
                exportPath = AudioSocket.getAudioFile(content, apiUrl, apiKey, apiSecret, appId, savePath);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return exportPath;
    }

}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值