教你用 Web Speech API 和 Node.js 來創建一個簡單的 AI 聊天機器人

簡評:使用語音命令在今天變得非常普遍,許多手機用戶使用像 Siri 和 Cortana 這樣的語音助手,我們的卧室也被亞馬遜的 Echo 和 Google Home 這樣的設備「入侵」了。這些系統都離不開語音識別軟體,現在,我們的瀏覽器也友好支持了 Web Speech API,可以讓用戶在 Web 應用中集成語音功能。

這篇文章將介紹如何使用 API 來在瀏覽器中創建人工智慧語音聊天界面。這個應用會識別用戶的聲音,並且用一個合成的聲音來回答用戶。因為 Web Speech API 還處在試驗階段,這個應用只在支持的瀏覽器上可用。這篇文章使用的語音識別和語音合成功能,目前僅在基於 Chromium 的瀏覽器上支持,包括 Chrome 25+ 和 Opera 27+,目前 Firefox,Edge 和 Safari 僅支持語音合成。

Chrome 上運行的 demo 視頻鏈接,接下來我們就來完成這個 demo !

要完成這個 Web 應用,我們需要完成下面三個主要的步驟:

1. 使用 Web Speech API 的 SpeechRecognition 介面來識別用戶的聲音;

2. 將用戶的消息作為文本字元串發送到商業的自然語言處理 API;

3. 一旦 API.AI 返回了響應文本,使用 SpeechSynthesis 介面來合成語音。

這篇文章使用的完整源代碼在 GitHub 上。(先幫妹子贊一個)

開始你的 Node.js 應用

首先,我們要用 Node.js 搭建一個 Web 應用框架。創建你的應用目錄,就像這樣:

.├── index.js├── public│ ├── css│ │ └── style.css│ └── js│ └── script.js└── views └── index.html

然後,執行下面的命令來初始化你的 Node.js 應用:

$ npm init -f

-f 命令表示接受默認的配置(你也可以去掉,然後手動配置你的應用),這樣會生成一個 package.json 文件,包含一些基本信息。

現在,安裝下面的依賴庫:

$ npm install express socket.io apiai --save

--save 命令將會在 package.json 中自動更新依賴。

我們將要使用 Express 庫,一個 Node.js 寫的 Web 應用服務框架,可以在本地運行伺服器。為了實現在瀏覽器和伺服器之間實時雙向交流,我們將會使用 Socket.IO。同時,我們將會安裝自然語音處理服務工具,API.AI用來構建一個 AI 聊天機器人。

Socket.IO 是一個在 Node.js 中輕鬆使用 WebSocket 的庫。通過在客戶端和服務端建立 socket 連接,只要 Web Speech API(語音消息)或者 API.AI API (AI 消息)返回了文本數據,我們的聊天信息就能在瀏覽器和伺服器之間往返。

現在,讓我們創建 index.js 文件,並實例化 Express 以及監聽伺服器:

const express = require("express");const app = express();app.use(express.static(__dirname + "/views")); // htmlapp.use(express.static(__dirname + "/public")); // js, css, imagesconst server = app.listen(5000);app.get("/", (req, res) => { res.sendFile("index.html");});

下一步,我們將使用 Web Speech API 集成前端代碼。

用 SpeechRecognition 介面接收語音

Web Speech API 有一個主要的控制介面,叫 SpeechRecognition,從麥克風接收用戶的語音並加以識別。

創建用戶界面

這個應用的 UI 很簡單:一個打開語音識別的按鈕。打開 index.html,將前端的 JavaScript 文件(script.js)和 Socket.IO 包含進去。

<html lang="en"> <head></head> <body><script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.1/socket.io.js"></script> <script src="js/script.js"></script> </body></html>

然後,我們在 body 中添加一個按鈕:

<button>Talk</button>

為了讓我們的按鈕看起來像 demo 中的那樣,我們需要在源代碼中引用 style.css 文件。

用 JavaScript 捕捉聲音

script.js 中,調用 SpeechRecognition 的實例,Web Speech API 的控制介面:

const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;const recognition = new SpeechRecognition();

我們同時使用了有前綴和沒有前綴的對象,因為 Chrome 目前支持 API 的前綴屬性。

同時,我們使用了 ECMAScript6 語法,因為 ES6,const 關鍵字和箭頭函數以及 Speech API 介面 SpeechRecognitionSpeechSynthesis 都在瀏覽器中支持。

你可以隨意地設置一些屬性變數來自定義語音識別:

recognition.lang = "en-US";recognition.interimResults = false;

然後,拿到按鈕的 DOM 引用,監聽點擊事件來初始化語音識別:

document.querySelector("button").addEventListener("click", () => { recognition.start();});

一旦開始語音識別,就能用 result 事件將剛剛說的話轉成文本:

recognition.addEventListener("result", (e) => { let last = e.results.length - 1; let text = e.results[last][0].transcript; console.log("Confidence: " + e.results[0][0].confidence); // We will use the Socket.IO here later…});

這將返回 SpeechRecognitionResultList 對象,你可以在這個對象的數組中得到文本結果。同時,你可以看到上面代碼中返回的 confidence 轉錄。

現在,是時候使用 Socket.IO 來向服務端發送文本了。

用 Socket.IO 實時交互

你可能會好奇為什麼我們不用簡單的 HTTP 或者 AJAX 來代替。你可以通過 POST 方法向服務端發送數據,但是,通過 Socket.IO,我們使用 WebSocket 發送數據,因為 socket 是雙向交流的最佳解決方案,尤其是當我們從服務端向瀏覽器推送事件時。通過持續的 socket 連接,我們不用重新載入瀏覽器或者頻繁地持續發送 AJAX 請求。

script.js 中實例化 Socket.IO

const socket = io();

然後插入你監聽 SpeechRecognition 的 result 事件代碼:

socket.emit("chat message", text);

現在重新回到 Node.js 代碼,接收這條文本,然後使用 AI 響應用戶。

從 AI 中得到答覆

許多平台和服務都能夠讓你在應用中用語音-文本自然語言處理來集成 AI 系統,包括 IBM 的 Watson,微軟的 LUIS 和 臉書的 Wit.ai。為了快速構建對話界面,我們將使用 API.AI,因為它提供了免費的開發者賬戶,讓我們可以使它的 Web 介面和 Node.js 庫快速地建立一個小型對話系統。

設置 API.AI

創建一個賬戶後,你就創建了一個「代理」。參考文檔指南的第一步。

接著,點擊左邊菜單的 「Small Talk」,然後開啟啟用服務選項。

用 API.AI 界面自定義你的 small-talk 代理。

點擊菜單中你的代理名字旁邊的齒輪圖標,回到 「基本設置」 頁面,拿到 API 密鑰。你將會在 Node.js SDK 中使用「客戶端訪問令牌」。

使用 API.AI

我們將使用 Node.js SDK 來將我們的 Node.js 應用連接到 API.AI。回到 index.js,用你的訪問令牌初始化 API.AI:

const apiai = require("apiai")(APIAI_TOKEN);

如果你只想在本地運行,你可以在這裡硬編碼你的 API 密鑰。這裡有幾種方式來設置環境變數,但我通常使用 .env 文件來聲明變數。在 GitHub 中的源碼中,我用 .gitignore 隱藏了我的證書文件。但是你可以參考 .env-test 文件看看它是如何設置的。

現在我們要用服務端的 Socket.IO 來接收瀏覽器的數據。

一旦建立連接收到消息,使用 API.AI 的介面來響應用戶:

io.on("connection", function(socket) { socket.on("chat message", (text) => { // Get a reply from API.AI let apiaiReq = apiai.textRequest(text, { sessionId: APIAI_SESSION_ID }); apiaiReq.on("response", (response) => { let aiText = response.result.fulfillment.speech; socket.emit("bot reply", aiText); // Send the result back to the browser! }); apiaiReq.on("error", (error) => { console.log(error); }); apiaiReq.end(); });});

當 API.AI 返回結果後,用 Socket.IO 的 socket.emit() 方法發送到客戶端。

用 SpeechSynthesis 介面讓 AI 發出聲音

回到 script.js,用 Web Speech API 的 SpeechSynthesis 控制器介面創建一個合成聲音的函數。這個函數接收一個字元串參數,讓瀏覽器讀出文本:

function synthVoice(text) { const synth = window.speechSynthesis; const utterance = new SpeechSynthesisUtterance(); utterance.text = text; synth.speak(utterance);}

上面的代碼首先創建了一個 window.speechSynthesis 這個 API 接入點,你可能會注意到這次是沒有前綴屬性的,這個 API 比 SpeechRecognition 更廣泛地被支持,所有的瀏覽器都棄用了 SpeechSysthesis 的前綴。

接著創建了一個 SpeechSynthesisUtterance() ,然後設置要被合成聲音的文本。你可以設置其他的屬性,比如 voice,來選擇瀏覽器和操作系統支持的聲音類型。最終調用 SpeechSynthesis.speak() 來發出聲音。

現在再次用 Socket.IO 來獲得服務端響應,一旦消息收到了,就調用上面的函數。

socket.on("bot reply", function(replyText) { synthVoice(replyText);});

讓我們來試試我們的 AI 機器人吧!

參考文章:

  • 「Web Speech API,」 Mozilla Developer Network
  • 「Web Speech API Specification,」 W3C
  • 「Web Speech API: Speech Synthesis」 (Microsoft Edge documentation) Microsoft
  • Guide, Node.js
  • Documentation, npm
  • 「Hello world example,」 Express
  • 「Get Started,」 Socket.IO

還可以試試不同的自然語言處理工具:

  • API.AI, Google
  • Wit.ai, Facebook
  • LUIS, Microsoft
  • Watson, IBM
  • Lex, Amazon

原文鏈接:Building A Simple AI Chatbot With Web Speech API And Node.js

推薦閱讀:

  • JavaScript 數組和對象就像書和報紙一樣

歡迎關註:知乎專欄「極光日報」,每天為 Makers 導讀三篇優質英文文章。


推薦閱讀:

TAG:JavaScript | Nodejs | 人工智能AI酱 |