教你用 Web Speech API 和 Node.js 來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的 AI 聊天機(jī)器人

簡(jiǎn)評(píng):使用語(yǔ)音命令在今天變得非常普遍,許多手機(jī)用戶(hù)使用像 Siri 和 Cortana 這樣的語(yǔ)音助手,我們的臥室也被亞馬遜的 Echo 和 Google Home 這樣的設(shè)備“入侵”了。這些系統(tǒng)都離不開(kāi)語(yǔ)音識(shí)別軟件,現(xiàn)在,我們的瀏覽器也友好支持了 Web Speech API,可以讓用戶(hù)在 Web 應(yīng)用中集成語(yǔ)音功能。

這篇文章將介紹如何使用 API 來(lái)在瀏覽器中創(chuàng)建人工智能語(yǔ)音聊天界面。這個(gè)應(yīng)用會(huì)識(shí)別用戶(hù)的聲音,并且用一個(gè)合成的聲音來(lái)回答用戶(hù)。因?yàn)?Web Speech API 還處在試驗(yàn)階段,這個(gè)應(yīng)用只在支持的瀏覽器上可用。這篇文章使用的語(yǔ)音識(shí)別和語(yǔ)音合成功能,目前僅在基于 Chromium 的瀏覽器上支持,包括 Chrome 25+ 和 Opera 27+,目前 Firefox,Edge 和 Safari 僅支持語(yǔ)音合成。

Chrome 上運(yùn)行的 demo 視頻鏈接,接下來(lái)我們就來(lái)完成這個(gè) demo !

要完成這個(gè) Web 應(yīng)用,我們需要完成下面三個(gè)主要的步驟:

  1. 使用 Web Speech API 的 SpeechRecognition 接口來(lái)識(shí)別用戶(hù)的聲音;
  2. 將用戶(hù)的消息作為文本字符串發(fā)送到商業(yè)的自然語(yǔ)言處理 API;
  3. 一旦 API.AI 返回了響應(yīng)文本,使用 SpeechSynthesis 接口來(lái)合成語(yǔ)音。


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

開(kāi)始你的 Node.js 應(yīng)用

首先,我們要用 Node.js 搭建一個(gè) Web 應(yīng)用框架。創(chuàng)建你的應(yīng)用目錄,就像這樣:

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

然后,執(zhí)行下面的命令來(lái)初始化你的 Node.js 應(yīng)用:

$ npm init -f

-f 命令表示接受默認(rèn)的配置(你也可以去掉,然后手動(dòng)配置你的應(yīng)用),這樣會(huì)生成一個(gè) package.json文件,包含一些基本信息。

現(xiàn)在,安裝下面的依賴(lài)庫(kù):

$ npm install express socket.io apiai --save

--save 命令將會(huì)在package.json 中自動(dòng)更新依賴(lài)。

我們將要使用 Express 庫(kù),一個(gè) Node.js 寫(xiě)的 Web 應(yīng)用服務(wù)框架,可以在本地運(yùn)行服務(wù)器。為了實(shí)現(xiàn)在瀏覽器和服務(wù)器之間實(shí)時(shí)雙向交流,我們將會(huì)使用 Socket.IO。同時(shí),我們將會(huì)安裝自然語(yǔ)音處理服務(wù)工具,API.AI用來(lái)構(gòu)建一個(gè) AI 聊天機(jī)器人。

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

現(xiàn)在,讓我們創(chuàng)建index.js 文件,并實(shí)例化 Express 以及監(jiān)聽(tīng)服務(wù)器:

const express = require('express');
const app = express();

app.use(express.static(__dirname + '/views')); // html
app.use(express.static(__dirname + '/public')); // js, css, images

const server = app.listen(5000);
app.get('/', (req, res) => {
  res.sendFile('index.html');
});

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

用 SpeechRecognition 接口接收語(yǔ)音

Web Speech API 有一個(gè)主要的控制接口,叫 SpeechRecognition,從麥克風(fēng)接收用戶(hù)的語(yǔ)音并加以識(shí)別。

創(chuàng)建用戶(hù)界面

這個(gè)應(yīng)用的 UI 很簡(jiǎn)單:一個(gè)打開(kāi)語(yǔ)音識(shí)別的按鈕。打開(kāi)index.html,將前端的 JavaScript 文件(script.js)和 Socket.IO 包含進(jìn)去。

<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>

然后,我們?cè)?body 中添加一個(gè)按鈕:

<button>Talk</button>

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

用 JavaScript 捕捉聲音

script.js中,調(diào)用 SpeechRecognition 的實(shí)例,Web Speech API 的控制接口:

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

我們同時(shí)使用了有前綴和沒(méi)有前綴的對(duì)象,因?yàn)?Chrome 目前支持 API 的前綴屬性。

同時(shí),我們使用了 ECMAScript6 語(yǔ)法,因?yàn)?ES6,const 關(guān)鍵字和箭頭函數(shù)以及 Speech API 接口 SpeechRecognitionSpeechSynthesis 都在瀏覽器中支持。

你可以隨意地設(shè)置一些屬性變量來(lái)自定義語(yǔ)音識(shí)別:

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

然后,拿到按鈕的 DOM 引用,監(jiān)聽(tīng)點(diǎn)擊事件來(lái)初始化語(yǔ)音識(shí)別:

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

一旦開(kāi)始語(yǔ)音識(shí)別,就能用 result 事件將剛剛說(shuō)的話(huà)轉(zhuǎn)成文本:

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 對(duì)象,你可以在這個(gè)對(duì)象的數(shù)組中得到文本結(jié)果。同時(shí),你可以看到上面代碼中返回的 confidence 轉(zhuǎn)錄。

現(xiàn)在,是時(shí)候使用 Socket.IO 來(lái)向服務(wù)端發(fā)送文本了。

Socket.IO 實(shí)時(shí)交互

你可能會(huì)好奇為什么我們不用簡(jiǎn)單的 HTTP 或者 AJAX 來(lái)代替。你可以通過(guò) POST 方法向服務(wù)端發(fā)送數(shù)據(jù),但是,通過(guò) Socket.IO,我們使用 WebSocket 發(fā)送數(shù)據(jù),因?yàn)?socket 是雙向交流的最佳解決方案,尤其是當(dāng)我們從服務(wù)端向?yàn)g覽器推送事件時(shí)。通過(guò)持續(xù)的 socket 連接,我們不用重新加載瀏覽器或者頻繁地持續(xù)發(fā)送 AJAX 請(qǐng)求。

script.js中實(shí)例化 http://Socket.IO

const socket = io();

然后插入你監(jiān)聽(tīng) SpeechRecognition 的 result 事件代碼:

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

現(xiàn)在重新回到 Node.js 代碼,接收這條文本,然后使用 AI 響應(yīng)用戶(hù)。

從 AI 中得到答復(fù)

許多平臺(tái)和服務(wù)都能夠讓你在應(yīng)用中用語(yǔ)音-文本自然語(yǔ)言處理來(lái)集成 AI 系統(tǒng),包括 IBM 的 Watson,微軟的 LUIS 和 臉書(shū)的 Wit.a。為了快速構(gòu)建對(duì)話(huà)界面,我們將使用 API.AI,因?yàn)樗峁┝嗣赓M(fèi)的開(kāi)發(fā)者賬戶(hù),讓我們可以使它的 Web 接口和 Node.js 庫(kù)快速地建立一個(gè)小型對(duì)話(huà)系統(tǒng)。

設(shè)置API.AI
創(chuàng)建一個(gè)賬戶(hù)后,你就創(chuàng)建了一個(gè)“代理”。參考文檔指南的第一步。

接著,點(diǎn)擊左邊菜單的 “Small Talk”,然后開(kāi)啟啟用服務(wù)選項(xiàng)。


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

點(diǎn)擊菜單中你的代理名字旁邊的齒輪圖標(biāo),回到 “基本設(shè)置” 頁(yè)面,拿到 API 密鑰。你將會(huì)在 Node.js SDK 中使用“客戶(hù)端訪(fǎng)問(wèn)令牌”。

使用API.AI
我們將使用 Node.js SDK 來(lái)將我們的 Node.js 應(yīng)用連接到 API.AI?;氐?index.js,用你的訪(fǎng)問(wèn)令牌初始化 API.AI:

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

如果你只想在本地運(yùn)行,你可以在這里硬編碼你的 API 密鑰。這里有幾種方式來(lái)設(shè)置環(huán)境變量,但我通常使用 .env 文件來(lái)聲明變量。在 GitHub 中的源碼中,我用 .gitignore 隱藏了我的證書(shū)文件。但是你可以參考 .env-test 文件看看它是如何設(shè)置的。

現(xiàn)在我們要用服務(wù)端的 Socket.IO 來(lái)接收瀏覽器的數(shù)據(jù)。

一旦建立連接收到消息,使用 API.AI 的接口來(lái)響應(yīng)用戶(hù):

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();

  });
});

當(dāng) API.AI 返回結(jié)果后,用 Socket.IOsocket.emit()方法發(fā)送到客戶(hù)端。

用 SpeechSynthesis 接口讓 AI 發(fā)出聲音

回到 script.js,用 Web Speech API 的 SpeechSynthesis 控制器接口創(chuàng)建一個(gè)合成聲音的函數(shù)。這個(gè)函數(shù)接收一個(gè)字符串參數(shù),讓瀏覽器讀出文本:

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

上面的代碼首先創(chuàng)建了一個(gè) window.speechSynthesis 這個(gè) API 接入點(diǎn),你可能會(huì)注意到這次是沒(méi)有前綴屬性的,這個(gè) API 比 SpeechRecognition 更廣泛地被支持,所有的瀏覽器都棄用了 SpeechSysthesis 的前綴。

接著創(chuàng)建了一個(gè) SpeechSynthesisUtterance() ,然后設(shè)置要被合成聲音的文本。你可以設(shè)置其他的屬性,比如 voice,來(lái)選擇瀏覽器和操作系統(tǒng)支持的聲音類(lèi)型。最終調(diào)用 SpeechSynthesis.speak() 來(lái)發(fā)出聲音。

現(xiàn)在再次用 Socket.IO 來(lái)獲得服務(wù)端響應(yīng),一旦消息收到了,就調(diào)用上面的函數(shù)。

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

讓我們來(lái)試試我們的 AI 機(jī)器人吧!


參考文章:

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

原文鏈接:Building A Simple AI Chatbot With Web Speech API And Node.js
推薦閱讀:
JavaScript 數(shù)組和對(duì)象就像書(shū)和報(bào)紙一樣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容