本文由
AI
辅助撰写,可能存在不准确之处,请读者注意甄别!
在这篇博客中,我将详细介绍如何使用HTML, JavaScript和Vue.js来实现一个基于Web的语音播报(TTS,Text-To-Speech)示例。这个示例允许用户触发播放文本、暂停/继续播放和停止播放操作。我们将使用微软的Azure TTS服务来将文本实时转为语音,再进行播放。
初始HTML结构和Vue.js集成
首先,我们的HTML文档以标准的<!DOCTYPE html>
声明开始,定义了一个简单的用户接口,它有三个按钮来控制文本的播放、暂停和停止。我们的HTML结构如下所示:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>语音播报示例</title>
<script src="https://unpkg.com/vue@3.2.16/dist/vue.global.prod.js"></script>
</head>
<body>
<div id="app">
<button @click="speak">播放文本</button>
<button @click="pause">暂停/继续</button>
<button @click="stop">停止</button>
</div>
<!-- 这里会接着放置我们的Vue和JavaScript代码 -->
</body>
</html>
这里我们包含了Vue.js,使用了它的全球CDN链接来轻松集成。
Vue.js应用构建
接下来,是创建Vue.js应用的脚本部分。我们从构建Vue应用开始,定义了一个state
对象来存储我们需要的各种属性。
const { createApp, reactive, ref } = Vue;
createApp({
setup() {
const state = reactive({
text: '你好,世界!',
pitch: 0,
rate: 30,
volume: 0,
lan: 'zh-CN',
voice: 0,
});
// ...更多代码将在后面添加
}
}).mount('#app');
在这个state
对象中,我们存储了要朗读的文本、语音的音高(pitch
)、速率(rate
)、音量(volume
)、使用的语言(lan
)还有特定的语音代号(voice
)。
与微软Azure TTS服务集成
要实现文本到语音的功能,我们需要和一个TTS服务进行通信。下面的例子中,示范如何与微软的Azure TTS服务通信:
function speak() {
const bufferList = [];
const ws = new WebSocket("wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1...");
// ...其他逻辑
}
在speak
方法中,我们新建了一个WebSocket连接到微软的TTS服务,并在连接打开后发送了两个消息:speechConfig
和ssmlText
,后者是根据给定状态构造的SSML(Speech Synthesis Markup Language)。
发送语音配置和SSML请求文本
我们先定义一个函数生成SSML请求和配置语音的请求头部。
const textEncoder = new TextEncoder();
const binaryHeadEnd = textEncoder.encode('Path:audio\r\n').toString();
const speechConfig = () => {
// ...配置信息
};
const ssmlText = (state, localVoiceList) => {
// ...SSML请求文本
};
其中,ssmlText
函数负责建立一个XML格式的消息体,它定义了将要转换成语音的文本,语音参数等。
WebSocket通信和事件处理
我们监听WebSocket的几个关键事件,例如message
事件,这是我们处理从服务器接收到的二进制音频数据的地方。
ws.addEventListener('message', async ({ data }) => {
// ...处理接收到的音频数据
});
ws.addEventListener('error', (err) => {
// ...处理错误事件
});
ws.addEventListener('close', () => {
// ...处理连接关闭事件
});
当接收到消息时,我们将音频数据的二进制拼接起来。最终在连接关闭事件中,用Blob
对象创建一个音频URL,并且用Audio
对象来播放它。
控制音频播放
我们创建函数来控制音频的播放,包括暂停和停止功能。
function pause() {
// 暂停或继续播放音频
}
function stop() {
// 停止音频的播放
}
在speak
函数结束时,我们返回了这些控制函数,这样它们就可以在Vue的模板中以方法的形式被绑定到按钮的点击事件上。最终Vue的setup
函数如下:
setup() {
// ...初始化state和其他响应式数据
// 定义speak, pause, stop函数
return {
speak,
pause,
stop,
};
}
完整代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>语音播报示例</title>
<script src="https://unpkg.com/vue@3.2.16/dist/vue.global.prod.js"></script>
</head>
<body>
<div id="app">
<button @click="speak">播放文本</button>
<button @click="pause">暂停/继续</button>
<button @click="stop">停止</button>
</div>
<script>
const { createApp, reactive, ref } = Vue;
const textEncoder = new TextEncoder();
const binaryHeadEnd = textEncoder.encode('Path:audio\r\n').toString();
const speechConfig = () => `X-Timestamp:${new Date().toISOString()}\r\nContent-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n{"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":"false","wordBoundaryEnabled":"true"},"outputFormat":"webm-24khz-16bit-mono-opus"}}}}`;
const ssmlText = (state, localVoiceList) => {
const requestId = guid();
return `X-RequestId:${requestId}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:${new Date().toISOString()}\r\nPath:ssml\r\n\r\n<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='https://www.w3.org/2001/mstts' xml:lang='${state.lan}'><voice name='${localVoiceList[state.lan][state.voice].Name}'><prosody pitch='${numToString(state.pitch)}Hz' rate ='${numToString(state.rate)}%' volume='${numToString(state.volume)}%'>${state.text}</prosody></voice></speak>`;
};
function guid(){
function gen(count) {
var out = "";
for (var i = 0; i < count; i++) {
out += (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return out;
}
return gen(8);
}
function numToString(num) {
return num >= 0 ? `+${num}` : `${num}`;
}
createApp({
setup() {
const state = reactive({
text: '你好,世界!我能为你做什么?',
pitch: 0,
rate: 30,
volume: 0,
lan: 'zh-CN',
voice: 0,
});
const localVoiceList = {
'zh-CN': [{ 'Name': 'zh-CN-XiaoxiaoNeural' }],
};
// 创建一个响应式引用来跟踪音频对象
const audio = ref(null);
function speak() {
const bufferList = [];
const ws = new WebSocket("wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=6A5AA1D4EAFF4E9FB37E23D68491D6F4");
ws.addEventListener('open', () => {
ws.send(speechConfig());
ws.send(ssmlText(state, localVoiceList));
});
ws.addEventListener('message', async ({ data }) => {
if (data instanceof Blob) {
const view = new Uint8Array(await data.arrayBuffer());
bufferList.push(...view.toString().split(binaryHeadEnd)[1].split(',').slice(1).map(i => +i));
if(view[0] == 0x00 && view[1] == 0x67 && view[2] == 0x58) {
ws.close(1000);
}
}
});
ws.addEventListener("error", (err) => {
console.error('WebSocket error', err);
});
ws.addEventListener('close', () => {
if(bufferList.length) {
const blob = new Blob([new Uint8Array(bufferList)], {type: 'audio/webm'});
const audioUrl = URL.createObjectURL(blob);
// 将Audio对象保存在Vue实例中
audio.value = new Audio(audioUrl);
audio.value.play();
} else {
console.error('No audio data received.');
}
});
}
// 暂停/继续播放的功能
function pause() {
if (audio.value) {
if (audio.value.paused) {
audio.value.play();
} else {
audio.value.pause();
}
}
}
// 停止播放的功能
function stop() {
if (audio.value) {
audio.value.pause(); // 暂停播放
audio.value.currentTime = 0; // 重置时间
}
}
return {
speak,
pause,
stop,
};
}
}).mount('#app');
</script>
</body>
</html>
结语
通过这个实现,我们展示了如何将文本转换为语音并在Web应用中播放。我们涉及到了Vue.js的基本应用构建、与第三方API集成的WebSocket通信以及HTML5的音频API的使用。这个基础示例可以被应用于更复杂的场景,比如构建一个完整的Web语音读取器,或者集成到聊天机器人中提升交互体验。希望这篇博客对你的项目有启发和帮助!
版权属于:soarli
本文链接:https://blog.soarli.top/archives/709.html
转载时须注明出处及本声明。