iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
Modern Web

JS30 x 鐵人30 x MDN doc系列 第 20

[Day20] - Speech Detection(JS30 x 鐵人 30 x MDN)

  • 分享至 

  • xImage
  •  

做一個網頁語音輸入功能,可將語音輸入的英文自動變成文字

  1. 創建語音識別實例:既然使用到語音識別那自然是使用到 Web Speech API 中的 SpeechRecognition,如一些內置物間一樣我們需要先 new 創建出一個實例儲存於一個變數中,並可以設定一些屬性後再開始調用他的獨有 method,在開始之前我們先來認識有哪些屬性可以設定吧

    (1) continuous(連續模式,Boolean):用於指定是否在使用者停止說話之前繼續監聽並識別語音。

    • 預設值:true
    • 示例範例:recognition.continuous = false;

    (2) grammars(語法規則,SpeechGrammarList Object):是指一個語法規則清單,用於指定與語音識別相關的語法規則。語法規則定義了語音輸入的語法和結構,可用於精確控制語音識別。

    • 示例範例:
    const grammarList = new SpeechGrammarList();
    //  只會識別這幾個單字
    grammarList.addFromString("color choices", "red | blue | green | yellow");
    
    // 將语語法規則指派給語音識別的grammars屬性
    recognition.grammars = grammarList;
    
    // 語音識別處理邏輯
    recognition.onresult = function (event) {
      const result = event.results[0][0].transcript;
      console.log("識別顏色:", result);
    };
    

    (3) interimResults(即時結果,Boolean):用於指定是否在語音識別過程中返回部分結果,而不僅僅是最終結果。當設置為 true 時,識別引擎將返回部分識別結果,講話途中會持續產生語音識別結果

    • 預設值:false
    • 用法範例:recognition.interimResults = true;

    (4) lang(語言,String):用於設定期望的語音識別語言。可以指定BCP 47格式的語言標記,以確保識別引擎能夠識別和適應相應的語言。

    • 預設值:瀏覽器或使用者設備的默認語言
    • 用法範例:recognition.lang = 'zh-TW';

    (5) maxAlternatives(最大替代方案,Interger):用於設定識別結果的最大替代方案數。這可用於獲取多個可能的識別結果,而不僅僅是最佳匹配。

    • 預設值:1
    • 示例範例:recognition.maxAlternatives = 3;

在了解以上屬性後,我決定要將這題改寫成一個能夠識別中文、可以邊說邊顯示結果的且連續識別的語音辨識功能就好,不需要侷限識別內容。

//  不同瀏覽器有不同的Web API命名,因此使用這行處理兼容性問題
window.SpeechRecognition =
  window.SpeechRecognition || window.webkitSpeechRecognition;
// 創建出一個語音識別實例
const recognition = new SpeechRecognition();
// 返回中途識別結果
recognition.interimResults = true;
// 設定識別語言為繁體中文
recognition.lang = "zh-TW";
  1. 定義語音識別啟動方式:我在 words 容器中新增了一個使用到Font Awesome麥克風 icon 的<a>tag,用來控制語音識別功能的啟動停止,當點擊時才會觸發語音識別,不像原作者的持續識別。
<div class="words">
  <a class="mic"><i class="fa-solid fa-microphone"></i></a>
</div>
  • 並新增、修改了以下樣式
.mic {
  position: absolute;
  top: 0;
  right: 20px;
  transform: translateY(25%);
  cursor: pointer;
}
.words {
  position: relative;
  padding: 2rem 2rem 2rem 5rem;
  /*其它維持原設定*/
}
  • 取得節點並新增事件監聽器,以及觸發事件後要執行的函式
//  語音識別結果渲染要渲染近的容器節點
const words = document.querySelector(".words");
//  啟動語音識別的麥克風節點
const mic = document.querySelector(".mic");
//  新增(滑鼠點擊)事件監聽器
mic.addEventListener("click", recognitionStart);

function recognitionStart(e) {
  //  把麥克風變成紅色
  mic.style.color = "red";
  //  創造一個<p>供放入識別結果,並插入至渲染容器最前面
  let p = document.createElement("p");
  words.insertBefore(p, words.firstChild);
  //  啟動語音識別
  recognition.start();
}
  1. 處理語音識別結果:既然我們已經啟動了語音識別,那麼識別結果會以什麼方式顯示呢?答案自然是存放在名為result event中,因此我們替這個語音識別實例新增一個(返回結果)監聽器,並先將 event 印出來查看,你會發現當你說了一句話時會觸發多次事件,還記得嗎?那是因為我們前面設定的recognition.interimResults = true; // 返回中途識別結果造成的,但不用擔心,語音識別 API 很聰明,在一定期間沒有偵測到語音輸入之後,便會自動停止識別,並有一個isFinal屬性判斷是否為最終識別結果。
//  替這個語音識別實例新增一個(返回結果)監聽器
recognition.addEventListener("result", (e) => {
  //  觀察事件內容
  console.log(e);
  //  取得words容器中第一個<p>tag,即最新(insertBefore)新增的
  const p = words.querySelector("p");
  //  從事件中提取識別結果
  const transcript = Array.from(e.results)
    .map((result) => result[0])
    .map((result) => result.transcript)
    .join("");
  //  替換識別結果中匹配到的打招呼字段,在後面新增emoji
  const greetReplaced = transcript.replace(/(你好|大家好)/g, "$1👋");
  //  將識別結果即時放在<p>tag中
  p.textContent = greetReplaced;
  //  判斷是否為最終結果,如果是
  if (e.results[0].isFinal) {
    //  <p>tag增加contenteditable屬性,讓內容可由使用者修改
    p.setAttribute("contenteditable", "");
    //  把麥克風的紅色清掉
    mic.style.color = "";
  }
});

👉Github Demo 頁面 👈

👉 好想工作室 15th 鐵人賽看板 👈

參考資料

  1. Javascript 30 官網
    https://javascript30.com/
  2. MDN 官網
    https://developer.mozilla.org/en-US/

上一篇
[Day19] - Webcam Fun(JS30 x 鐵人 30 x MDN)
下一篇
[Day21] - Geolocation(JS30 x 鐵人 30 x MDN)
系列文
JS30 x 鐵人30 x MDN doc30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言