Web Speech API (SpeechSynthesisUtterance)
2023-06-27
Web Speech API 的 SpeechSynthesisUtterance 物件是一個強大的工具,可以在網頁上合成語音,而不需要繁瑣的引用,只需要單純的 JS,它的原理是使用瀏覽器本身的 API 實作,因此不同的瀏覽器,提供不同的語音選擇。
Code
<!doctype html>
<html lang="en">
<head>
<title>Web Speech API</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS v5.2.1 -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
</head>
<body>
<div class="container p-5">
<form action="">
<div class="mb-3">
<label for="" class="form-label">Text</label>
<textarea name="text" id="text" cols="30" rows="10"
class="form-control">Haha, I don't think that would work for me. Maybe I just need to get more sleep and stop staying up so late watching TV.</textarea>
</div>
<div class="mb-3">
<label for="" class="form-label">Voice</label>
<select class="form-select" name="" id=""></select>
</div>
<div class="mb-3">
<label for="" class="form-label">Ratio</label>
<input type="range" min="0" max="2" value="1" step="0.1" class="form-control" name="" id="rate"
aria-describedby="helpId" placeholder="">
</div>
<div class="mb-3">
<label for="" class="form-label">Pitch</label>
<input type="range" min="0" max="2" value="1" step="0.1" class="form-control" name="" id="pitch"
aria-describedby="helpId" placeholder="">
</div>
<button type="submit" class="btn btn-primary">Speak</button>
</form>
</div>
<script>
const synth = window.speechSynthesis;
const inputForm = document.querySelector("form");
const inputTxt = document.querySelector("#text");
const voiceSelect = document.querySelector("select");
const rate = document.querySelector("#rate");
const pitch = document.querySelector("#pitch");
let voices;
function loadVoices() {
voices = synth.getVoices();
for (let i = 0; i < voices.length; i++) {
if (voices[i].lang.includes("en-US")) {
const option = document.createElement("option");
option.textContent = `${voices[i].name} (${voices[i].lang})`;
option.value = i;
voiceSelect.appendChild(option);
}
else {
console.log(voices[i].lang);
}
}
}
// in Google Chrome the voices are not ready on page load
if ("onvoiceschanged" in synth) {
synth.onvoiceschanged = loadVoices;
} else {
loadVoices();
}
inputForm.onsubmit = (event) => {
event.preventDefault();
const utterThis = new SpeechSynthesisUtterance(inputTxt.value);
utterThis.voice = voices[voiceSelect.value];
utterThis.rate = rate.value;
utterThis.pitch = pitch.value;
synth.speak(utterThis);
inputTxt.blur();
};
</script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"
integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
integrity="sha384-7VPbUDkoPSGFnVtYi0QogXtr74QeVeeIs99Qfg5YCF+TidwNdjvaKZX19NZ/e6oz" crossorigin="anonymous">
</script>
</body>
</html>
在示範程式碼當中,透過 voices[i].lang.includes("en-US")
限定 SELECT 只出現英語,如果有需要其他語言的 Speech 可以移除此搜尋限制。