Uso del servicio de texto a voz de Microsoft en uni-app

Estoy participando en la convocatoria de ensayos para tecnología cruzada. Para obtener más información, consulte: juejin.cn/post/710123...

prefacio

He probado varias soluciones TTS y, después de un poco de experiencia, descubrí que Microsoft es el rey en este campo y Azure文本转语音que el efecto de voz convertido de sus servicios es el más natural, pero Azure es un servicio pago y es demasiado problemático para pagar. para operaciones de registro. Pero en su sitio web oficial, en realidad proporciona una 完全体función de demostración, que puede experimentar completamente las voces y los estilos de habla de todos los personajes...

imagen.png

Pero simplemente no se puede descargar como un mp3archivo, por lo que algunos amigos tienen que transcribir la voz de la computadora para obtener el archivo de audio, pero esto es demasiado problemático. De hecho, todos los recursos que se pueden ver y escuchar en la página web son el resultado del descifrado. Es decir, siempre que el sonido se reproduzca desde la página web, debemos encontrar la manera de extraer el archivo de audio.

Este artículo es para registrar todo el proceso de exploración y realización, disfrute ~

La mayor parte del contenido de este artículo fue escrito a principios de este año y aún no se ha publicado. Sé que una vez que este método se haga público, pronto será bloqueado por Microsoft, o incluso cancelará directamente la entrada y las interfaces relacionadas de la experiencia web.

Analizar la función de demostración del sitio web oficial de Azure

Use el navegador Chrome para abrir el panel de depuración Cuando hacemos clic en la 播放función en el sitio web oficial de Azure, podemos monitorear una wss://solicitud desde la pestaña de red, que es una websocketsolicitud.

imagen.png

dos parámetros

En la solicitud URL, podemos ver que hay dos parámetros AuthorizationyX-ConnectionId

imagen.png

Curiosamente, el primer parámetro está en el código fuente de la página web y puede extraerlo directamente solicitando axiosesta URL de texto a voz de Azure.get

imagen.png

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;
}
复制代码

Al ver la pila de llamadas JS que inició la solicitud, haga clic en reproducir nuevamente después de agregar un punto de interrupción

imagen.png

imagen.png

Se puede encontrar que el segundo parámetro X-ConnectionIdproviene de una createNoDashGuidfunción

this.privConnectionId = void 0 !== t ? t : s.createNoDashGuid(),
复制代码

这就是一个uuid v4格式的字符串,nodash就是没有-的意思。

三次发送

请求时URL里的两个参数已经搞定了,我们继续分析这个webscoket请求,从Message标签中可以看到

imagen.png

每次点击播放时,都向服务器上报了三次数据,明显可以看出来三次上报数据各自的作用

第一次的数据:SDK版本,系统信息,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"}}}
复制代码

第二次的数据:转语音输出配置,从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}}}
复制代码

第三次的数据:要转语音的文本信息和角色voice name,语速rate,语调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%">我叫大帅,一个热爱编程的老程序猿</prosody></voice></speak>
复制代码

接收的二进制消息

既然从前三次上报的信息已经看出来返回的格式就是mp3文件了,那么我们是不是把所有返回的二进制数据合并就可以拼接成完整的mp3文件了呢?答案是肯定的!

每次点击播放后接收的所有来自websocket的消息的最后一条,都有明确的结束标识符

imagen.png

imagen.png

turn.end代表转换结束!

用Node.js实现它

既然都解析出来了,剩下的就是在Node.js中重新实现这个过程。

两个参数

  1. Authorization,直接通过axios的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 Authorization = RegExp.$1;
}
复制代码
  1. X-ConnectionId,直接使用uuid库即可
//npm install uuid
const { v4: uuidv4 } = require('uuid');

const XConnectionId = uuidv4().toUpperCase();
复制代码

创建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);
复制代码

三次发送

第一次发送

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);
复制代码

第二次发送

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);
复制代码

第三次发送

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%">
                我叫大帅,一个热爱编程的老程序猿
                </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);
复制代码

接收二进制消息拼接mp3

当三次发送结束后我们通过connect.on('binary')监听websocket接收的二进制消息。

Cree un objeto Buffer vacío final_datay luego empalme el contenido binario recibido cada vez en final_dataél. Una vez que el mensaje de texto normal contenga un Path:turn.endidentificador, se final_dataescribirá y creará en un mp3archivo.

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)]);
    })
});
复制代码

De esta manera, guardamos con éxito el mp3archivo de audio sin siquiera abrir el sitio web oficial de Azure.

herramienta de línea de comandos

He empaquetado todo el código en una herramienta de línea de comandos, es muy fácil de usar

npm install -g mstts-js
mstts -i 文本转语音 -o ./test.mp3
复制代码

Todo código abierto: github.com/ezshine/mst…

usar en uni-aplicación

Crear una nueva función en la nube

Cree una nueva función en la nube y asígnele un nombremstts imagen.png

Como mstss-jsha sido encapsulado, solo necesita estar en la función de la nube y npm install mstts-jsluego requireel código es el siguiente

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

exports.main = async (event, context) => {
    const res = await mstts.getTTSData('要转换的文本','CN-Yunxi');
   
    //res为buffer格式
});
复制代码

Descargar y reproducir archivos mp3

Para reproducir este archivo en formato mp3 en uniapp, hay dos formas

Método 1. Cargue primero en el almacenamiento en la nube y acceda a través de la dirección de almacenamiento en la nube

exports.main = async (event, context) => {
    const res = await mstts.getTTSData('要转换的文本','CN-Yunxi');
   
    //res为buffer格式
    var uploadRes = await uniCloud.uploadFile({
        cloudPath: "xxxxx.mp3",
        fileContent: res
    })
    
    return uploadRes.fileID;
});
复制代码

Uso frontal:

uniCloud.callFunction({
    name:"mstts",
    success:(res)=>{
        const aud = uni.createInnerAudioContext();
        aud.autoplay = true;
        aud.src = res;
        aud.play();
    }
})
复制代码
  • Pros: seguridad de la función de la nube
  • Desventaja: Subir archivos al almacenamiento en la nube sin un mecanismo de limpieza desperdiciará espacio

Método 2. Utilice la URLización + respuesta integrada de las funciones de la nube para acceder

Este método consiste en convertir directamente el cuerpo de respuesta de la función de la nube en un archivo mp3, al que audio.srcse puede acceder directamente a través de la asignación .

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

Uso frontal:

const aud = uni.createInnerAudioContext();
aud.autoplay = true;
aud.src = 'https://ezshine-274162.service.tcloudbase.com/mstts';
aud.play();
复制代码
  • Pros: fácil de usar, no es necesario guardar archivos en el almacenamiento en la nube
  • Desventaja: si la función de nube URLizada no tiene un mecanismo de seguridad, otros pueden usarla arbitrariamente después de ser capturada.

resumen

Una biblioteca tan útil tts, si te ayuda, no olvides githubapoyarla star.


Soy 大帅, un programa que ama programar . WeChat personal:dashuailaoyuan

Supongo que te gusta

Origin juejin.im/post/7103720862221598757
Recomendado
Clasificación