1. 程式人生 > >jacob和百度語音合成 播報的實現形式

jacob和百度語音合成 播報的實現形式

有個語音播報的需求,這些日子查了一些資料,在這裡總結一下,一些工具類和檔案我已經放到了下載路徑上,下面提供

1,jacob

引入maven

<!-- https://mvnrepository.com/artifact/net.sf.jacob-project/jacob -->
    <dependency>
      <groupId>net.sf.jacob-project</groupId>
      <artifactId>jacob</artifactId>
      <version>1.14.3</version>
    </dependency>

將jacob-1.14.3-x64放在jdk的bin中,和C:\WINDOWS\System32中,注意放入的jacob和maven下載版本要一致

實現程式碼如下

public static void stratVoice(String content, int type) {
       ActiveXComponent sap = new ActiveXComponent("Sapi.SpVoice");
       Dispatch sapo = sap.getObject();
       if (type == 0) {
           try {
               // 音量 0-100
               sap.setProperty("Volume", new Variant(100));
               // 語音朗讀速度 -10 到 +10
               sap.setProperty("Rate", new Variant(0));
               Variant defalutVoice = sap.getProperty("Voice");
               Dispatch dispdefaultVoice = defalutVoice.toDispatch();
               Variant allVoices = Dispatch.call(sapo, "GetVoices");
               Dispatch dispVoices = allVoices.toDispatch();

               Dispatch setvoice = Dispatch.call(dispVoices, "Item",
                       new Variant(1)).toDispatch();
               ActiveXComponent voiceActivex = new ActiveXComponent(
                       dispdefaultVoice);
               ActiveXComponent setvoiceActivex = new ActiveXComponent(
                       setvoice);
               Variant item = Dispatch.call(setvoiceActivex, "GetDescription");
               // 執行朗讀
               Dispatch.call(sapo, "Speak", new Variant(content));
           } catch (Exception e) {
               log.info("錯誤:", e);
               e.printStackTrace();
           } finally {
               sapo.safeRelease();
               sap.safeRelease();
           }
       } else {
           // 停止
           try {
               Dispatch.call(sapo, "Speak", new Variant(content), new Variant(
                       2));
           } catch (Exception e) {
               System.out.println(e.getMessage());
               e.printStackTrace();
           }
       }
   }

引用

public static void main(String[] args) {
       VoiceUtil.stratVoice("桃之夭夭,灼灼其華。之子于歸,宜其室家。\n" +
               "桃之夭夭,有蕡其實。之子于歸,宜其家室。\n" +
               "桃之夭夭,其葉蓁蓁。之子于歸,宜其家人", 0);
   }

可以自己玩一下引數

2,百度語音合成(服務端播報)

可以先看下文件瞭解下,下面先引maven

<!-- https://mvnrepository.com/artifact/com.baidu.aip/java-sdk -->
    <dependency>
      <groupId>com.baidu.aip</groupId>
      <artifactId>java-sdk</artifactId>
      <version>4.3.2</version>
    </dependency>

這是主要程式碼,具體去連結下載即可

public String voiceRun(HttpServletRequest request){
        try {
            TokenHolder holder = new TokenHolder(appKey, secretKey, TokenHolder.ASR_SCOPE);
            holder.refresh();
            String token = holder.getToken();
            // 此處2次urlencode, 確保特殊字元被正確編碼
            String params = "tex=" + ConnUtil.urlEncode(ConnUtil.urlEncode(text));
            params += "&per=" + per;
            params += "&spd=" + spd;
            params += "&pit=" + pit;
            params += "&vol=" + vol;
            params += "&cuid=" + cuid;
            params += "&tok=" + token;
            params += "&aue=" + aue;
            params += "&lan=zh&ctp=1";
            log.info("反饋請帶上此url,瀏覽器上可以測試:{}", url + "?" + params); // 反饋請帶上此url,瀏覽器上可以測試
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setConnectTimeout(5000);
            PrintWriter printWriter = new PrintWriter(conn.getOutputStream());
            printWriter.write(params);
            printWriter.close();
            String contentType = conn.getContentType();
            if (contentType.contains("audio/")) {
                byte[] bytes = ConnUtil.getResponseBytes(conn);
                String format = getFormat(aue);
                // 第二種:獲取專案路徑
                File directory = new File("");// 引數為空
                String path = request.getSession().getServletContext().getRealPath("/");
                System.out.println(path);
                File file = new File(path + "result." + format); // 開啟mp3檔案即可播放
                FileOutputStream os = new FileOutputStream(file);
                os.write(bytes);
                os.close();
                log.info("儲存路徑:{}", file.getAbsolutePath());
//                boolean ret = voiceStart(format);
//                log.info("播放結果:{}", ret);
                return "success";
            } else {
                System.err.println("ERROR: content-type= " + contentType);
                String res = ConnUtil.getResponseString(conn);
                System.err.println(res);
                return null;
            }
        }catch (Exception e){
            return null;
        }
    }
request.getSession().getServletContext().getRealPath("/");這個獲取的是專案根目錄,是wav檔案的存放路徑,等會播報會用到

播放wav

public static boolean voiceStart(String format) {
        try {
            log.info("播放開始,{}", System.getProperty("user.dir"));
            // 1.wav 檔案放在java project 下面 即可播放
            FileInputStream fileau = new FileInputStream(
                    System.getProperty("user.dir") + "\\result." + format);
            AudioStream as = null;
            as = new AudioStream(fileau);
            AudioPlayer.player.start(as);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

這裡面播報用到的路徑我沒改,不應該用System.getProperty("user.dir")這個獲取,我當時就沒獲取到這個路徑,也應該用剛才存路徑的那個request.getSession().getServletContext().getRealPath("/"),如果你本地main測試可以先寫死

wav檔案保留30天,30天后失效,所以播報可以放在外面,30天內都可以直接呼叫播報即可,不用重複生成,還要想辦法如何在30天內最低會呼叫一次voiceRun合成語音介面,使wav檔案不至於失效播報不出來,這個就自己想辦法吧

因為是伺服器端播報,如果想聽到聲音要遠端連線,如果關閉了連線就聽不到了,這個如果有大神知道如何解決這個問題請留言告知

3,百度語音合成:客戶端播報

客戶端可以先用上面已用voiceRun生成wav檔案,然後定義一個div

<div id="emb"></div>

用js實現業務呼叫

function myrefresh() {
        $.ajax({
            type: "GET",
            url: "/server/status",
            dataType: "json",
            data: "",
            success: function (data) {
                var res = data.res;
                if (res != 0) {
                    //根據業務
                    var data = "<embed id=\"wavFileId\"\n" +
                        "       src=\"/YQStore/result.wav\"\n" +
                        "       width=\"0\"\n" +
                        "       height=\"0\"\n" +
                        "       loop=\"false\"\n" +
                        "       autostart=\"false\">\n" +
                        "</embed>";
                    $('#emb').html(data);
                    console.log("語音提醒")
                    try {
                        var node = document.getElementById('wavFileId');
                        if(node!=null){
                            node.Play();
                        }
                    } catch (err) {
                        console.log("err->" + err)
                    }
                }
                setTimeout('myrefresh()', 5000); //指定5秒重新整理一次
            },
            error: function () {
                setTimeout('myrefresh()', 5000); //指定5秒重新整理一次
            }
        });
    }
    setTimeout('myrefresh()', 5000);

5s鍾重新整理一次根據業務進行播報,src就是wav後端存的路徑

這樣就可以實現在本地可以聽到語音播報了,但是有個缺點就是如果不在當前頁面就會聽不到聲音,不過可以將頁面單獨拉出來放在後面,再操作自己的網頁就不影響播報了,如果有大神有更好的辦法望告知,謝謝