/

語音合成 API

語音合成 API

語音合成 API 是一個非常棒的工具,現代瀏覽器提供了這個 API,讓我們能夠嘗試建立新型的介面並讓瀏覽器與使用者互相對話。

該 API 於 2014 年被引入,現在已經被廣泛採用,Chrome、Firefox、Safari 和 Edge 都已提供支持。不過,IE 不支援。

語音合成 API 的瀏覽器支援

它是 Web 語音 API 的一部分,還包括「語音辨識 API」,不過目前只有 Chrome 在實驗模式下支援該功能。

最簡單的使用語音合成 API 的示例是一行程式碼:

1
speechSynthesis.speak(new SpeechSynthesisUtterance('嗨'))

將其複製並貼到瀏覽器控制台中,你的電腦應該會開始說話!

API

該 API 會將一些物件公開給 window 物件。

SpeechSynthesisUtterance

SpeechSynthesisUtterance 表示一個語音請求。在上面的例子中,我們將字符串作為參數傳給它,這是瀏覽器應該要朗讀的內容。

一旦獲得了語音請求物件,你可以對它進行一些調整,以編輯語音的屬性:

1
const utterance = new SpeechSynthesisUtterance('嗨')
  • utterance.rate:設置語速,接受區間為 [0.1 - 10],預設為 1
  • utterance.pitch:設置音調,接受區間為 [0 - 2],預設為 1
  • utterance.volume:設置音量,接受區間為 [0 - 1],預設為 1
  • utterance.lang:設置語言(使用 BCP 47 語言標籤,如 en-USit-IT
  • utterance.text:可以在建構函式中設置,也可以作為屬性傳入。文本長度不能超過 32767 個字符。
  • utterance.voice:設置語音(關於這個後面會說明更多)

以下是一個示例:

1
2
3
4
5
const utterance = new SpeechSynthesisUtterance('嗨')
utterance.pitch = 1.5
utterance.volume = 0.5
utterance.rate = 8
speechSynthesis.speak(utterance)

選擇一個語音

瀏覽器提供了不同數量的語音。

使用以下程式碼查看語音列表:

1
2
3
4
5
console.log(`語音數量:${speechSynthesis.getVoices().length}`)

speechSynthesis.getVoices().forEach(voice => {
console.log(voice.name, voice.lang)
})

Firefox 中的語音

這是一個跨瀏覽器的問題。上面的程式碼在 Firefox 和 Safari(可能也包括 Edge,但我沒有測試過)中運作正常,但在 Chrome 中不起作用。Chrome 使用不同的方式來處理語音,並要求在語音加載完成後呼叫回調函式:

1
2
3
4
5
6
7
const voiceschanged = () => {
console.log(`語音數量:${speechSynthesis.getVoices().length}`)
speechSynthesis.getVoices().forEach(voice => {
console.log(voice.name, voice.lang)
})
}
speechSynthesis.onvoiceschanged = voiceschanged

在回調函式被調用之後,我們可以使用 speechSynthesis.getVoices() 方法來獲得語音列表。

我相信這是因為 Chrome(如果有網絡連接)會從 Google 伺服器檢查其他語言:

Chrome 的語言設置

如果沒有網絡連接,可用語言的數量與 Firefox 和 Safari 相同。附加的語言僅在網絡已啟用的地方提供,但該 API 也可以在離線狀態下運作。

跨瀏覽器實現語言選擇

由於存在這種差異,我們需要一種方法來抽象化它以使用這個 API。以下示例演示了如何實現這種抽象化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const getVoices = () => {
return new Promise(resolve => {
let voices = speechSynthesis.getVoices()
if (voices.length) {
resolve(voices)
return
}
speechSynthesis.onvoiceschanged = () => {
voices = speechSynthesis.getVoices()
resolve(voices)
}
})
}

const printVoicesList = async () => {
;(await getVoices()).forEach(voice => {
console.log(voice.name, voice.lang)
})
}

printVoicesList()

在 Glitch 上查看

使用自訂語言

預設的語音是使用英文發音的。你可以使用任何語言,只需設置 utterance 的 lang 屬性即可:

1
2
3
let utterance = new SpeechSynthesisUtterance('Ciao')
utterance.lang = 'it-IT'
speechSynthesis.speak(utterance)

使用其他語音

如果有多個語音可用,你可能想選擇其他語音。例如,預設的意大利語音是女性聲音,但也許我想要男性聲音,那就是語音列表中的第二個語音。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const lang = 'it-IT'
const voiceIndex = 1

const speak = async text => {
if (!speechSynthesis) {
return
}
const message = new SpeechSynthesisUtterance(text)
message.voice = await chooseVoice()
speechSynthesis.speak(message)
}

const getVoices = () => {
return new Promise(resolve => {
let voices = speechSynthesis.getVoices()
if (voices.length) {
resolve(voices)
return
}
speechSynthesis.onvoiceschanged = () => {
voices = speechSynthesis.getVoices()
resolve(voices)
}
})
}

const chooseVoice = async () => {
const voices = (await getVoices()).filter(voice => voice.lang === lang)

return new Promise(resolve => {
resolve(voices[voiceIndex])
})
}

speak('Ciao')

在 Glitch 上查看

語言的值

以下是你可以使用的一些語言的示例:

  • 阿拉伯語(沙特阿拉伯)➡️ ar-SA
  • 中文(中國)➡️ zh-CN
  • 中文(香港特別行政區中國)➡️ zh-HK
  • 中文(台灣)➡️ zh-TW
  • 捷克語(捷克共和國)➡️ cs-CZ
  • 丹麥語(丹麥)➡️ da-DK
  • 荷蘭語(比利時)➡️ nl-BE
  • 荷蘭語(荷蘭)➡️ nl-NL
  • 英語(澳大利亞)➡️ en-AU
  • 英語(愛爾蘭)➡️ en-IE
  • 英語(南非)➡️ en-ZA
  • 英語(英國)➡️ en-GB
  • 英語(美國)➡️ en-US
  • 芬蘭語(芬蘭)➡️ fi-FI
  • 法語(加拿大)➡️ fr-CA
  • 法語(法國)➡️ fr-FR
  • 德語(德國)➡️ de-DE
  • 希臘語(希臘)➡️ el-GR
  • 印地語(印度)➡️ hi-IN
  • 匈牙利語(匈牙利)➡️ hu-HU
  • 印度尼西亞語(印尼)➡️ id-ID
  • 意大利語(義大利)➡️ it-IT
  • 日語(日本)➡️ ja-JP
  • 韓語(南韓)➡️ ko-KR
  • 挪威語(挪威)➡️ no-NO
  • 波蘭語(波蘭)➡️ pl-PL
  • 葡萄牙語(巴西)➡️ pt-BR
  • 葡萄牙語(葡萄牙)➡️ pt-PT
  • 羅馬尼亞語(羅馬尼亞)➡️ ro-RO
  • 俄語(俄羅斯)➡️ ru-RU
  • 斯洛伐克語(斯洛伐克)➡️ sk-SK
  • 西班牙語(墨西哥)➡️ es-MX
  • 西班牙語(西班牙)➡️ es-ES
  • 瑞典語(瑞典)➡️ sv-SE
  • 泰語(泰國)➡️ th-TH
  • 土耳其語(土耳其)➡️ tr-TR

移動裝置

在 iOS 上,這個 API 是可以工作的,但必須由使用者操作回調函式觸發,例如對點擊事件的回應,以提供更好的用戶體驗,避免手機發出意外的聲音。

在桌面版中,你無法像在桌面版中那樣讓網頁突然發出聲音。