您好,登錄后才能下訂單哦!
本篇內容主要講解“調用AI api實現網頁文字朗讀的方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“調用AI api實現網頁文字朗讀的方法”吧!
京東云上提供了足夠多的人工智能api,并且都使用了http的方式進行了封裝,用戶可以方便在自己的系統中接入京東云的ai能力。今天就是介紹一下如何編寫很少的代碼就能使用京東云的語音合成api在網頁中實現文字朗讀,最終實現效果,延遲小,支持主流設備,聲調優美,還能男女生切換。
最終效果,微信打開鏈接,點擊播放按鈕則可以進行文字朗讀。
京東云AI API使用Restful接口風格,同時提供了java和python的sdk,使用sdk能夠方便的封裝參數,調用api獲得數據。
為了提升調用方的響應速度,語音合成api采用了分段合成的模式,所以調用的時候在后端邏輯中按順序多次調用,將音頻數據以數據流的形式回寫給前端。
訪問京東云api需要獲取 ak sk ,配合sdk使用;
進入京東云控制臺-賬號管理-Access Key管理,創建并獲取Access Key。
這里給出后端部分源碼,實現一個controller,開發一個get請求方法,參數封裝的邏輯全都提煉出單獨的方法,代碼邏輯結構簡單易懂。代碼使用fastJson處理參數,另外引用了京東云sdk,其余都是jdk自帶的api,依賴很少。
1 import com.alibaba.fastjson.JSON; 2 import com.alibaba.fastjson.JSONObject; 3 import com.wxapi.WxApiCall.WxApiCall; 4 import com.wxapi.model.RequestModel; 5 6 import org.springframework.stereotype.Controller; 7 import org.springframework.web.bind.annotation.GetMapping; 8 import org.springframework.web.bind.annotation.RequestHeader; 9 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 import java.io.IOException; 13 import java.io.OutputStream; 14 import java.util.Base64; 15 import java.util.HashMap; 16 import java.util.Map; 17 18 @Controller 19 public class TTSControllerExample { 20 //url appkey secretkey 21 private static final String url = "https://aiapi.jdcloud.com/jdai/tts"; 22 private static final String appKey = ""; 23 private static final String secretKey = ""; 24 25 @GetMapping("/tts/stream/example") 26 public void ttsStream( 27 @RequestHeader(value = "Range", required = false) String range, 28 HttpServletRequest req, 29 HttpServletResponse resp) { 30 31 //應對safari的第一次確認請求攜帶header Range:bytes=0-1,此時回寫1byte數據,防止錯誤 32 if ("bytes=0-1".equals(range)) { 33 try { 34 byte[] temp = new byte['a']; 35 resp.setHeader("Content-Type", "audio/mp3"); 36 OutputStream out = resp.getOutputStream(); 37 out.write(temp); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 return; 42 } 43 //封裝輸入參數 44 Map queryMap = processQueryParam(req); 45 String text = req.getParameter("text"); 46 //封裝api調用請求報文 47 RequestModel requestModel = getBaseRequestModel(queryMap, text); 48 try { 49 //回寫音頻數據給前端 50 writeTtsStream(resp, requestModel); 51 } catch (IOException e) { 52 e.printStackTrace(); 53 } 54 } 55 56 /** 57 * 將前端輸入參數封裝為api調用的請求對象,同時設置url appkey secaretKey 58 * @param queryMap 59 * @param bodyStr 60 * @return 61 */ 62 private RequestModel getBaseRequestModel(Map queryMap, String bodyStr) { 63 RequestModel requestModel = new RequestModel(); 64 requestModel.setGwUrl(url); 65 requestModel.setAppkey(appKey); 66 requestModel.setSecretKey(secretKey); 67 requestModel.setQueryParams(queryMap); 68 requestModel.setBodyStr(bodyStr); 69 return requestModel; 70 } 71 72 /** 73 * 流式api調用,需要將sequenceId 依次遞增,用該方法進行設置請求對象sequenceId 74 * @param sequenceId 75 * @param requestModel 76 * @return 77 */ 78 private RequestModel changeSequenceId(int sequenceId, RequestModel requestModel) { 79 requestModel.getQueryParams().put("Sequence-Id", sequenceId); 80 return requestModel; 81 } 82 83 /** 84 * 將request中的請求參數封裝為api調用請求對象中的queryMap 85 * @param req 86 * @return 87 */ 88 private Map processQueryParam(HttpServletRequest req) { 89 String reqid = req.getParameter("reqid"); 90 int tim = Integer.parseInt(req.getParameter("tim")); 91 String sp = req.getParameter("sp"); 92 93 JSONObject parameters = new JSONObject(8); 94 parameters.put("tim", tim); 95 parameters.put("sr", 24000); 96 parameters.put("sp", sp); 97 parameters.put("vol", 2.0); 98 parameters.put("tte", 0); 99 parameters.put("aue", 3); 100 101 JSONObject property = new JSONObject(4); 102 property.put("platform", "Linux"); 103 property.put("version", "1.0.0"); 104 property.put("parameters", parameters); 105 106 Map<String, Object> queryMap = new HashMap<>(); 107 //訪問參數 108 queryMap.put("Service-Type", "synthesis"); 109 queryMap.put("Request-Id", reqid); 110 queryMap.put("Protocol", 1); 111 queryMap.put("Net-State", 1); 112 queryMap.put("Applicator", 1); 113 queryMap.put("Property", property.toJSONString()); 114 115 return queryMap; 116 } 117 118 /** 119 * 循環調用api,將音頻數據回寫到response對象 120 * @param resp 121 * @param requestModel 122 * @throws IOException 123 */ 124 public void writeTtsStream(HttpServletResponse resp, RequestModel requestModel) throws IOException { 125 //分段獲取音頻sequenceId從1遞增 126 int sequenceId = 1; 127 changeSequenceId(sequenceId, requestModel); 128 //設置返回報文頭內容類型為audio/mp3 129 resp.setHeader("Content-Type", "audio/mp3"); 130 //api請求sdk對象 131 WxApiCall call = new WxApiCall(); 132 //獲取輸出流用于輸出音頻流 133 OutputStream out = resp.getOutputStream(); 134 call.setModel(requestModel); 135 //解析返回報文,獲得status 136 String response = call.request(); 137 JSONObject jsonObject = JSON.parseObject(response); 138 JSONObject data = jsonObject.getJSONObject("result"); 139 //第一次請求增加校驗,如果錯誤則向前端回寫500錯誤碼 140 if (data.getIntValue("status") != 0) { 141 resp.sendError(500, data.getString("message")); 142 return; 143 } 144 //推送實際音頻數據 145 String audio = data.getString("audio"); 146 byte[] part = Base64.getDecoder().decode(audio); 147 out.write(part); 148 out.flush(); 149 //判斷是否已結束,多次請求對應多個index,index<0 代表最后一個包 150 if (data.getIntValue("index") < 0) { 151 return; 152 } 153 //循環推送剩余部分音頻 154 while (data.getIntValue("index") >= 0) { 155 //sequenceid 遞增 156 sequenceId = sequenceId + 1; 157 changeSequenceId(sequenceId, requestModel); 158 //請求api獲得新的音頻數據 159 call.setModel(requestModel); 160 response = call.request(); 161 jsonObject = JSON.parseObject(response); 162 data = jsonObject.getJSONObject("result"); 163 audio = data.getString("audio"); 164 part = Base64.getDecoder().decode(audio); 165 //回寫新的音頻數據 166 out.write(part); 167 out.flush(); 168 } 169 } 170 171 172 173 前端audio播放朗讀 174 前端部分給出在vue 模塊化開發中的script部分,由于采用html5的audio進行語音播放,為了兼容性需要引用howler.js (npm install howler),主要邏輯為根據設置的參數和待朗讀的文字拼接一個url,調用howler.js 中的api進行播放。 175 176 <script> 177 import {Howl, Howler} from 'howler' 178 export default { 179 data() { 180 return { 181 news: { // 新聞內容 182 …… 183 }, 184 role: 1, // 0女聲,1男聲 185 speed: 1, // 播放速度 186 curIndex: -1, // 播放的段落在所有段落中的順序,與用戶交互顯示相關,與流式播放無關 187 sound: null, // 頁面唯一的指向howler實例的變量 188 status: 'empty' // load,pause,stop,empty 僅與用戶交互顯示相關,與流式播放顯示無關 189 } 190 }, 191 methods: { 192 generateUUID () { // 生成uuid 193 let d = Date.now() 194 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { 195 let r = (d + Math.random() * 16) % 16 | 0 196 d = Math.floor(d / 16) 197 return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16) 198 }) 199 }, 200 audioSrc (txt) { // 生成獲取音頻的鏈接 201 let content = encodeURI(txt) // 文字編碼 202 return `http://neuhubdemo.jd.com/api/tts/streamv2?reqid=${ 203 this.generateUUID() // requestID 204 }&text=${ 205 content // 編碼后的文字內容 206 }&tim=${ 207 this.role // 男聲 or 女聲 208 }&sp=${ 209 this.speed // 播放速度 210 }` 211 }, 212 /** 213 * 獲取文案對應的流式音頻 214 * 215 * 使用howler能夠解決部分手機瀏覽器(eg:UC)的兼容問題, 216 * 但解決ios上微信和safari的兼容問題, 217 * 需要后端通過{range:bytes=0-1}這個header字段對請求進行控制 218 * @param {String 待轉音頻的文案} txt 219 */ 220 howlerPlay(txt) { 221 if (this.sound) { 222 this.sound.unload() // 若sound已有值,則銷毀原對象 223 } 224 let self = this 225 this.status = 'load' 226 this.sound = new Howl({ 227 src: `${this.audioSrc(txt)}`, 228 html5: true, // 必須!A live stream can only be played through HTML5 Audio. 229 format: ['mp3', 'aac'], 230 // 以下onplay、onpause、onend均為控制顯示相關 231 onplay() { 232 self.status = 'pause' 233 }, 234 onpause: function() { 235 self.status = 'stop' 236 }, 237 onend: function() { 238 self.status = 'stop' 239 } 240 }); 241 this.sound.play() 242 }, 243 // 控制用戶交互 244 play (txt, index) { 245 if (this.curIndex === index) { 246 if (this.status === 'stop') { 247 this.sound.play() 248 } else { 249 this.sound.pause() 250 } 251 } else { 252 this.curIndex = index 253 this.howlerPlay(txt) 254 } 255 } 256 } 257 } 258 </script>
到此,相信大家對“調用AI api實現網頁文字朗讀的方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。