本篇開箱Web Speech API提供了瀏覽器內建的文字轉語音功能。
大家應該用過Google的語音功能吧?其實我們可以透過Web Speech API就能實現簡單的文字轉語音功能喔!
Web Speech API 中的 SpeechSynthesis是語音服務的控制介面;它可以用來取得裝置上可用的合成聲音的訊息,開始、暫停語音,或除此之外的其他指令。
前往>>MDN 範例Demo
前往>>MDN 範例程式碼
你可以貼到瀏覽器檢查工具console貼上以下程式碼就能播出了喔!
const synthesis = window.speechSynthesis;
const utterance = new SpeechSynthesisUtterance('這裡是文字');
synthesis.speak(utterance);
SpeechSynthesis.cancel():移除所有語音談話隊列中的談話。
SpeechSynthesis.getVoices(): 傳回目前裝置所有可用聲音的清單。
SpeechSynthesis.pause():把SpeechSynthesis物件為暫停狀態。
SpeechSynthesis.resume():把SpeechSynthesis物件為非暫停狀態:如果已經暫停了則
繼續。
SpeechSynthesis.speak():增加一個utterance到語音談話隊列;它會在其他語音播放
完之後播放。
SpeechSynthesisUtterance.lang: 設定語音的語言
SpeechSynthesisUtterance.pitch:設定語音的音調(音高)範圍從0(最小)到2(最大)。預設值為1
SpeechSynthesisUtterance.rate:設定說話的速度。預設值是1,範圍是0.1到10,表示語速
的倍數,例如2表示正常語速的兩倍
SpeechSynthesisUtterance.text:設定在語音時將合成的文字内容。
SpeechSynthesisUtterance.voice: 設定用於說話的聲音。
SpeechSynthesisUtterance.volume:設定將在其中發言的音量。區間範圍是0到1,預設是1
那我們今天就把MDN的範例改寫成vue3吧!
Demo網址:https://hahasister-ironman-project.netlify.app/#/textToSpeech
備註:
-本人實測一下成果,音調
有時候沒效果是語系的關係,如果你輸入是中文,要測試音調的不同,請選「google國語台灣」
-預設值的聲音為"Mei-Jia",查了一下應該是https://harposoftware.com/en/mandarin-taiwan/378-mei-jia-nuance-voice.html
<template>
<div class="container">
<h1>文字轉語音</h1>
<p>說明:請在下面的輸入框中輸入文字,再按下"播放”按钮播放。</p>
<p>備註:可調整語音速度/音調/發音語系</p>
<hr />
<form @submit.prevent="speak" class="pt-8">
<label for="txt">輸入文字</label>
<textarea
id="txt"
v-model="inputTxt"
rows="4"
class="w-[80%] block p-2.5 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
placeholder="請輸入文字"
></textarea>
<div>
<label for="rate">速度</label>
<input
v-model="rateValue"
type="range"
min="0.5"
max="2"
step="0.1"
id="rate"
/>
<div class="rate-value">{{ rateValue }}</div>
<div class="clearfix"></div>
</div>
<div>
<label for="pitch">音調</label>
<input
v-model="pitchValue"
type="range"
min="0"
max="2"
step="0.1"
id="pitch"
/>
<div class="pitch-value">{{ pitchValue }}</div>
<div class="clearfix"></div>
</div>
<select
v-model="selectedVoice"
class="block p-2.5 w-full bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
>
<option v-for="voice in voices" :key="voice.name" :value="voice.name">
{{ `${voice.name} (${voice.lang})`
}}{{ voice.default ? '(預設)' : '' }}
</option>
</select>
<div class="controls">
<button id="play" type="submit" class="border border-gray-300">
播放
</button>
</div>
</form>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const inputTxt = ref('');
const selectedVoice = ref('');
const rateValue = ref(1);
const pitchValue = ref(1);
const voices = ref([]);
const synth = window.speechSynthesis;
const populateVoiceList = () => {
voices.value = synth
.getVoices()
.sort((a, b) => a.name.toUpperCase().localeCompare(b.name.toUpperCase()));
console.log('voices清單', voices.value);
if (!selectedVoice.value && voices.value.length > 0) {
selectedVoice.value = voices.value.filter(i => i.default == true)[0].name;
}
};
const speak = () => {
if (synth.speaking) {
synth.cancel();
console.log('speechSynthesis.speaking');
return;
}
if (inputTxt.value !== '') {
const utterThis = new SpeechSynthesisUtterance(inputTxt.value);
utterThis.onend = () => {
console.log('SpeechSynthesisUtterance.onend');
};
utterThis.onerror = () => {
console.error('SpeechSynthesisUtterance.onerror');
};
for (const voice of voices.value) {
if (voice.name === selectedVoice.value) {
utterThis.voice = voice;
break;
}
}
utterThis.pitch = pitchValue.value;
utterThis.rate = rateValue.value;
synth.speak(utterThis);
}
};
onMounted(() => {
populateVoiceList();
if (synth.onvoiceschanged !== undefined) {
synth.onvoiceschanged = populateVoiceList;
}
});
</script>
那我們明天再見了~
參考資料
https://blog.csdn.net/qq_32963841/article/details/118304543
https://ithelp.ithome.com.tw/articles/10196799