欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何在uni-app使用微軟的文字轉(zhuǎn)語音服務(wù)

 更新時(shí)間:2022年06月01日 09:17:33   作者:大帥老猿  
有了語音識(shí)別,交流就會(huì)變得很簡單,下面這篇文章主要給大家介紹了關(guān)于如何在uni-app使用微軟的文字轉(zhuǎn)語音服務(wù)的相關(guān)資料,需要的朋友可以參考下

前言

嘗試過各種TTS的方案,一番體驗(yàn)下來,發(fā)現(xiàn)微軟才是這個(gè)領(lǐng)域的王者,其Azure文本轉(zhuǎn)語音服務(wù)的轉(zhuǎn)換出的語音效果最為自然,但Azure是付費(fèi)服務(wù),注冊操作付費(fèi)都太麻煩了。但在其官網(wǎng)上竟然提供了一個(gè)完全體的演示功能,能夠完完整整的體驗(yàn)所有角色語音,說話風(fēng)格...

但就是不能下載成mp3文件,所以有一些小伙伴逼不得已只好通過轉(zhuǎn)錄電腦的聲音來獲得音頻文件,但這樣太麻煩了。其實(shí),能在網(wǎng)頁里看到聽到的所有資源,都是解密后的結(jié)果。也就是說,只要這個(gè)聲音從網(wǎng)頁里播放出來了,我們必然可以找到方法提取到音頻文件。

本文就是記錄了這整個(gè)探索實(shí)現(xiàn)的過程,請盡情享用~

本文大部分內(nèi)容寫于今年年初一直按在手里未發(fā)布,我深知這個(gè)方法一旦公之于眾,可能很快會(huì)迎來微軟的封堵,甚至直接取消網(wǎng)頁體驗(yàn)的入口和相關(guān)接口。

解析Azure官網(wǎng)的演示功能

使用Chrome瀏覽器打開調(diào)試面板,當(dāng)我們在Azure官網(wǎng)中點(diǎn)擊播放功能時(shí),可以從network標(biāo)簽中監(jiān)控到一個(gè)wss://的請求,這是一個(gè)websocket的請求。

兩個(gè)參數(shù)

在請求的URL中,我們可以看到有兩個(gè)參數(shù)分別是Authorization和X-ConnectionId

有意思的是,第一個(gè)參數(shù)就在網(wǎng)頁的源碼里,使用axios對這個(gè)Azure文本轉(zhuǎn)語音的網(wǎng)址發(fā)起get請求就可以直接提取到

const res = await axios.get("https://azure.microsoft.com/en-gb/services/cognitive-services/text-to-speech/");

const reg = /token: \"(.*?)\"/;

if(reg.test(res.data)){
    const token = RegExp.$1;
}

通過查看發(fā)起請求的JS調(diào)用棧,加入斷點(diǎn)后再次點(diǎn)擊播放

可以發(fā)現(xiàn)第二個(gè)參數(shù)X-ConnectionId來自一個(gè)createNoDashGuid的函數(shù)

this.privConnectionId = void 0 !== t ? t : s.createNoDashGuid(),

這就是一個(gè)uuid v4格式的字符串,nodash就是沒有-的意思。

三次發(fā)送

請求時(shí)URL里的兩個(gè)參數(shù)已經(jīng)搞定了,我們繼續(xù)分析這個(gè)webscoket請求,從Message標(biāo)簽中可以看到

每次點(diǎn)擊播放時(shí),都向服務(wù)器上報(bào)了三次數(shù)據(jù),明顯可以看出來三次上報(bào)數(shù)據(jù)各自的作用

第一次的數(shù)據(jù):SDK版本,系統(tǒng)信息,UserAgent

Path: speech.config
X-RequestId: 818A1E398D8D4303956D180A3761864B
X-Timestamp: 2022-05-27T16:45:02.799Z
Content-Type: application/json

{"context":{"system":{"name":"SpeechSDK","version":"1.19.0","build":"JavaScript","lang":"JavaScript"},"os":{"platform":"Browser/MacIntel","name":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36","version":"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"}}}

第二次的數(shù)據(jù):轉(zhuǎn)語音輸出配置,從outputFormat可以看出來,最終的音頻格式為audio-24khz-160kbitrate-mono-mp3,這不就是我們想要的mp3文件嗎?!

Path: synthesis.context
X-RequestId: 091963E8C7F342D0A8E79125EA6BB707
X-Timestamp: 2022-05-27T16:48:43.340Z
Content-Type: application/json

{"synthesis":{"audio":{"metadataOptions":{"bookmarkEnabled":false,"sentenceBoundaryEnabled":false,"visemeEnabled":false,"wordBoundaryEnabled":false},"outputFormat":"audio-24khz-160kbitrate-mono-mp3"},"language":{"autoDetection":false}}}

第三次的數(shù)據(jù):要轉(zhuǎn)語音的文本信息和角色voice name,語速rate,語調(diào)pitch,情感等配置

Path: ssml
X-RequestId: 091963E8C7F342D0A8E79125EA6BB707
X-Timestamp: 2022-05-27T16:48:49.594Z
Content-Type: application/ssml+xml

<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="zh-CN-XiaoxiaoNeural"><prosody rate="0%" pitch="0%">我叫大帥,一個(gè)熱愛編程的老程序猿</prosody></voice></speak>

接收的二進(jìn)制消息

既然從前三次上報(bào)的信息已經(jīng)看出來返回的格式就是mp3文件了,那么我們是不是把所有返回的二進(jìn)制數(shù)據(jù)合并就可以拼接成完整的mp3文件了呢?答案是肯定的!

每次點(diǎn)擊播放后接收的所有來自websocket的消息的最后一條,都有明確的結(jié)束標(biāo)識(shí)符

turn.end代表轉(zhuǎn)換結(jié)束!

用Node.js實(shí)現(xiàn)它

既然都解析出來了,剩下的就是在Node.js中重新實(shí)現(xiàn)這個(gè)過程。

兩個(gè)參數(shù)

  • Authorization,直接通過axios的get請求抓取網(wǎng)頁內(nèi)容后通過正則表達(dá)式提取
const res = await axios.get("https://azure.microsoft.com/en-gb/services/cognitive-services/text-to-speech/");

const reg = /token: \"(.*?)\"/;

if(reg.test(res.data)){
    const Authorization = RegExp.$1;
}
  • X-ConnectionId,直接使用uuid庫即可
//npm install uuid
const { v4: uuidv4 } = require('uuid');

const XConnectionId = uuidv4().toUpperCase();

創(chuàng)建WebSocket連接

//npm install nodejs-websocket
const ws = require("nodejs-websocket");

const url = `wss://eastus.tts.speech.microsoft.com/cognitiveservices/websocket/v1?Authorization=${Authorization}&X-ConnectionId=${XConnectionId}`;
const connect = ws.connect(url);

三次發(fā)送

第一次發(fā)送

function getXTime(){
    return new Date().toISOString();
}

const message_1 = `Path: speech.config\r\nX-RequestId: ${XConnectionId}\r\nX-Timestamp: ${getXTime()}\r\nContent-Type: application/json\r\n\r\n{"context":{"system":{"name":"SpeechSDK","version":"1.19.0","build":"JavaScript","lang":"JavaScript","os":{"platform":"Browser/Linux x86_64","name":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0","version":"5.0 (X11)"}}}}`;

connect.send(message_1);

第二次發(fā)送

const message_2 = `Path: synthesis.context\r\nX-RequestId: ${XConnectionId}\r\nX-Timestamp: ${getXTime()}\r\nContent-Type: application/json\r\n\r\n{"synthesis":{"audio":{"metadataOptions":{"sentenceBoundaryEnabled":false,"wordBoundaryEnabled":false},"outputFormat":"audio-16khz-32kbitrate-mono-mp3"}}}`;

connect.send(message_2);

第三次發(fā)送

const SSML = `
    <speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US">
        <voice name="zh-CN-XiaoxiaoNeural">
            <mstts:express-as style="general">
                <prosody rate="0%" pitch="0%">
                我叫大帥,一個(gè)熱愛編程的老程序猿
                </prosody>
            </mstts:express-as>
        </voice>
    </speak>
    `
const message_3 = `Path: ssml\r\nX-RequestId: ${XConnectionId}\r\nX-Timestamp: ${getXTime()}\r\nContent-Type: application/ssml+xml\r\n\r\n${SSML}`

connect.send(message_3);

接收二進(jìn)制消息拼接mp3

當(dāng)三次發(fā)送結(jié)束后我們通過connect.on('binary')監(jiān)聽websocket接收的二進(jìn)制消息。

創(chuàng)建一個(gè)空的Buffer對象final_data,然后將每一次接收到的二進(jìn)制內(nèi)容拼接到final_data里,一旦監(jiān)聽到普通文本消息中包含Path:turn.end標(biāo)識(shí)時(shí)則將final_data寫入創(chuàng)建一個(gè)mp3文件中。

let final_data=Buffer.alloc(0);
connect.on("text", (data) => {
    if(data.indexOf("Path:turn.end")>=0){
        fs.writeFileSync("test.mp3",final_data);
        connect.close();
    }
})
connect.on("binary", function (response) {
    let data = Buffer.alloc(0);
    response.on("readable", function () {
        const newData = response.read()
        if (newData)data = Buffer.concat([data, newData], data.length+newData.length);
    })
    response.on("end", function () {
        const index = data.toString().indexOf("Path:audio")+12;
        final_data = Buffer.concat([final_data,data.slice(index)]);
    })
});

這樣我們就成功的保存出了mp3音頻文件,連Azure官網(wǎng)都不用打開!

命令行工具

我已經(jīng)將整個(gè)代碼打包成一個(gè)命令行工具,使用非常簡單

npm install -g mstts-js
mstts -i 文本轉(zhuǎn)語音 -o ./test.mp3

已全部開源: github.com/ezshine/mst…

在uni-app中使用

新建一個(gè)云函數(shù)

新建一個(gè)云函數(shù),命名為mstts

由于mstss-js已經(jīng)封裝好了,只需要在云函數(shù)中npm install mstts-js然后require即可,代碼如下

'use strict';
const mstts = require('mstts-js')

exports.main = async (event, context) => {
    const res = await mstts.getTTSData('要轉(zhuǎn)換的文本','CN-Yunxi');
   
    //res為buffer格式
});

下載播放mp3文件

要在uniapp中播放這個(gè)mp3格式的文件,有兩種方法

方法1. 先上傳到云存儲(chǔ),通過云存儲(chǔ)地址訪問

exports.main = async (event, context) => {
    const res = await mstts.getTTSData('要轉(zhuǎn)換的文本','CN-Yunxi');
   
    //res為buffer格式
    var uploadRes = await uniCloud.uploadFile({
        cloudPath: "xxxxx.mp3",
        fileContent: res
    })
    return uploadRes.fileID;
});

前端用法:

uniCloud.callFunction({
    name:"mstts",
    success:(res)=>{
        const aud = uni.createInnerAudioContext();
        aud.autoplay = true;
        aud.src = res;
        aud.play();
    }
})
  • 優(yōu)點(diǎn):云函數(shù)安全
  • 缺點(diǎn):文件上傳到云存儲(chǔ)不做清理機(jī)制的話會(huì)浪費(fèi)空間

方法2. 利用云函數(shù)的URL化+集成響應(yīng)來訪問

這種方法就是直接將云函數(shù)的響應(yīng)體變成一個(gè)mp3文件,直接通過audio.src賦值即可訪問`

exports.main = async (event, context) => {
	const res = await mstts.getTTSData('要轉(zhuǎn)換的文本','CN-Yunxi');
	
	return {
		mpserverlessComposedResponse: true,
		isBase64Encoded: true,
		statusCode: 200,
		headers: {
			'Content-Type': 'audio/mp3',
			'Content-Disposition':'attachment;filename=\"temp.mp3\"'
		},
		body: res.toString('base64')
	}
};

前端用法:

const aud = uni.createInnerAudioContext();
aud.autoplay = true;
aud.src = 'https://ezshine-274162.service.tcloudbase.com/mstts';
aud.play();
  • 優(yōu)點(diǎn):用起來很簡單,無需保存文件到云存儲(chǔ)
  • 缺點(diǎn):URL化后的云函數(shù)如果沒有安全機(jī)制,被抓包后可被其他人肆意使用

小結(jié)

這么好用的tts庫,如果對你有所幫助別忘了在github里點(diǎn)個(gè)star支持一下。

總結(jié)

到此這篇關(guān)于如何在uni-app使用微軟的文字轉(zhuǎn)語音服務(wù)的文章就介紹到這了,更多相關(guān)uni-app文字轉(zhuǎn)語音服務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論