[Actions on Google 課程筆記] 透過 Dialogflow + Firebase + Line 輕鬆打造自己的智慧助理

「Hey,Google,今天天氣如何?」

你也開始跟手機對話了嗎?自從我知道可以用語音取代打字輸入之後,就回不去拉,實在是太方便了!明明說幾句話就能搞定,何必在那邊敲鍵盤呢?搞不好還不小心打錯字

在這個人工智慧大肆崛起的年代,語音辨識的誤判率早已明顯降低,而且語音輸入在許多無法使用鍵盤的場合也能使用,比如你在開車、走路或是洗澡(?)的時候,都可以透過聲音呼叫個人助理幫你辦事

這次參加了由 Girls in Tech 與 Taipei Women in Tech 聯合舉辦的 Actions on Google 課程,號稱是全球前 25 名舉辦的活動,也是台灣的第一場活動,似乎覺得自己走在時代的前端?哈哈,總之這是為了配合 Google 推廣 Actions on Google 才有的免費講座,當然要來聽聽看囉


甚麼是 Action on Google

Action on Google 就是在 Google 智慧助理上的應用服務

想像一下,你想要學習如何製作青醬義大利麵,這時候你問了 Google,他便根據網路上搜尋到的資料,提供你相關的答案,而這個動作就是一個 Action。Action 可以是簡單的查詢資料,也可以是一項複雜的任務,好比他可以當作訂房機器人或是客服小幫手,利用預先訓練好的內容,解決顧客的問題

請支持《傑瑞窩在這》原創文章。原文標題:[Actions on Google 課程筆記] 透過 Dialogflow + Firebase + Line 輕鬆打造自己的智慧助理,原文網址:https://jerrynest.io/actions-on-google/
Actions on Google 讓您走在電腦新浪潮的尖端,除了目前就可以在 Google Home 順利整合您的服務與 Google 個人助理,在不久的將來也能在可支援 Google 個人助理的其他體驗與裝置上進行整合

目前 Google 大力推廣 Action on Google,希望透過 Developer Community Program 吸引更多的開發者加入創作、累積能量,讓 Google 個人助理、Google Home 變得更加強大


打造自己的個人助理

之前看同學修「對話機器人」課程,要用深度學習的方式去訓練客服小幫手,由於是土炮建置,有很多東西都是要自己建,弄起來相當複雜。但如果我們只是想要體驗對話機器人、個人助理的威力,倒是不用重造輪子,透過現成的服務就能輕鬆地搭建

以 Google 生態系為例,使用者會透過 Google Home 這類的智慧裝置與 Google Assistant 溝通,系統串聯 Dialogflow (理解語意)、Firebase (處理邏輯)、Google Cloud (儲存資料) 來製作出一個類似交談的迴路。流程如下:

當然,並不是所有人都有 Google Home,所以 Dialogflow 除了接收 Google Assistant 送進來的對話資料,還可以接收其他平台,例如 Facebook Messenger、Line、Slack、Telegram 等等。總而言之,語意理解的部分交給 Dialogflow 做就行了,你要做的事情就是專心地開發應用邏輯

這次的課程主要是根據 Google Codelab 延伸而來,可惜寫完文章之後,原本的課程居然被移除了,現在只能參考 GitHub 上的範例教學:

[GitHub] Actions on Google: Facts about Google Sample using Node.js and Cloud Functions for Firebase

而目前 Codelab 上取而代之的是 Level1 與 Level2 課程,我想應該配合這幾天的 Google I/O 大會吧 XDDD

Build Actions for the Google Assistant (Level 1)
Build Actions for the Google Assistant (Level 2)

為什麼個人助理能理解你說的話?

這個範例 Facts About You,顧名思義就是要傳達一些事實,機器人會根據預先設定好的資料回答問題

比如範例準備了一些關於 Google 的歷史故事,使用者每次提出問題,機器人就會隨機挑一個預設好的答案回答,同時也準備了幾張貓咪的照片,當你問起貓咪的時候,機器人就會推送可愛的貓咪照給你

那麼 Dialogflow 要怎麼理解你問的是歷史故事,還是貓咪呢?這就回歸到對話機器人怎麼解析文字了,簡單來說,機器人會透過 Intent (意圖) 與 Entity (實例) 來理解你所說的話

  • Intent:有點像是一句話,比如「我要看有三隻貓咪的照片」
  • Entity:有點像關鍵字「三隻、貓咪」

參考下方的流程圖,所以當你說出「我要看有三隻貓咪的照片」,機器人根據你的 Intent 判斷出你說的話屬於「貓咪」這個類別,抽出「三隻」這個關鍵字,然後去尋找一張含有三隻貓咪的圖片給你

尋找一張含有三隻貓咪的圖片這件事情,就是我們要實作邏輯的地方。對應到下方的「fulfillment web service」,這部分是透過 Firebase 建立起來的 Function,每當有 Intent 被觸發,Dialogflow 就會呼叫我們實作的 Function,當我們處裡玩邏輯運算後,資料會透過 Webhook 回傳給 Dialogflow,接著 Dialogflow 再回應使用者


實作練習

上面這個範例比較像是 Content-based 的機器人,回答的問題都已經預先設定好,只是隨機送出來而已,但實際上的應用肯定是要串接 API 撈資料的,便想說來練習寫一個會呼叫 API 查詢資料的機器人

在 Dialogflow 的網站上有 Weather Sample 這個教學,他會教你怎麼用 Dialogflow 去呼叫 World Weather Online 的 API 取得天氣資料。不過我這邊稍微改一下,串接中央氣象局的 API,來顯示當天的氣象資訊 (因為中央氣象局的 API 只能撈整陀資料,我就偷懶不針對時間做查詢了)


實作練習 Part1 – Dialogflow

在 Dialogflow 要先設定好 Entity,讓機器人知道有那些關鍵字。比如我們要查詢各地的天氣狀況,就要先設定好「台北」、「台中」這些地名與他們的同義字

之後要設定 Intent,輸入一些訓練資料讓機器人學習,之後他聽到相關句子就會知道是在詢問「天氣」

在 Dialogflow 的 Integration 設定中,可以輕鬆的讓你串接到不同平台

實作練習 Part2 – Firebase

我們使用的是 Firebase Function 功能。在這裡可以看到 Function 被呼叫的狀況,假如有錯誤發生也能在這邊做簡單的除錯

const functions = require('firebase-functions');
const https = require('https');
const xml2js = require('xml2js');

const key = '';

function parseData(result) {
  let timeSlot = [];
  const dataset = result.cwbopendata.dataset[0].location;
  const data = dataset.map((location) => {
    const payload = {};
    const name = location.locationName[0];
    const timeElements = location.weatherElement[0].time;
    const timeElementDict = timeElements.map((element) => {
      const discribe = element.parameter[0].parameterName[0];
      const value = element.parameter[0].parameterValue[0];
      return { discribe, value };
    });
    timeSlot = timeElements.map(element => new Date(Date.parse(element.startTime[0])));
    payload.name = name;
    payload.data = timeElementDict;
    return payload;
  });
  return { data, time: timeSlot };
}

function getResponseObj(message) {
  return {
    fulfillmentMessages: [{
      text: {
        text: [message],
      },
    }],
    source: '',
  };
}

function generateCityMessage(obj, city) {
  const weatherNow = obj.data.find(d => d.name === city).data[0];
  const str = `${city}現在的氣溫是 ${weatherNow.value} 度,${weatherNow.discribe}`;
  return getResponseObj(str);
}


exports.helloHttp = functions.https.onRequest((request, response) => {
  // Get the city and date from the request
  const city = request.body.queryResult.parameters['taiwan-city'];
  const parser = new xml2js.Parser();

  // Get weather with cwb API and parse xml data to json
  https.get(`https://opendata.cwb.gov.tw/opendataapi?dataid=F-C0032-001&authorizationkey=${key}`, (res) => {
    let responsData = '';
    res.setEncoding('utf8');
    res.on('data', (chunk) => {
      responsData += chunk;
    });
    res.on('end', () => {
      parser.parseString(responsData, (err, result) => {
        let responseMessage;
        if (err) {
          responseMessage = response.json(getResponseObj('糟糕,出錯了'));
          console.log(`Cannot parse string: ${err.message}`);
        } else {
          const data = parseData(result);
          responseMessage = response.json(generateCityMessage(data, city));
        }
        return responseMessage;
      });
    });
    res.on('error', (err) => {
      console.log(`Cannot get response: ${err.message}`);
      return response.json(getResponseObj('糟糕,出錯了'));
    });
  });
});

完整的程式碼我放在 GitHub,有興趣的話可以參考

https://github.com/jlee58/weather-bot

實作練習 Part3 – Line Developer

Facebook Messenger 要審查比較麻煩,所以我試著串 Line bot,沒想到還挺容易的,幾分鐘就能搞定 XDD

特別注意的是,因為我們是自己處理回應邏輯,可以把 Line 本身的自動回應機制「Auto-reply messages」關掉,免得使用者收到兩個回應喔

在手機上運作的樣子,但為啥是 12 度?最近應該沒有這麼冷啊 XDD 不知道是誰的 Bug 哈哈


結語

實際走訪對話機器人的製作過程,會覺得這些工具實在很方便,之前覺得很麻煩的東西,可能現在串接幾下就搞定了。比如要來製作一個有獎徵答遊戲,其實就可以透過機器人出題,使用者回答完之後,直接將結果回傳至後端。如此一來,使用者可以不用額外下載 APP、不需要另外綁定帳號,也因為在服務建置在聊天平台上,在行銷推廣上也比較有利

對話機器人創造一個新的舞台,透過語音的方式來解決問題。儘管現在還在萌芽推廣階段,但我相信之後會有越來越多應用服務推出,也會有更多人接受它,畢竟人與人之間的交談是最直接的方式,或許有一天,我們的個人助理也能像《鋼鐵人》之中的賈維斯一樣善解人意 XDD


延伸閱讀

如果您覺得這篇文章有幫助,歡迎按個讚或分享出去唷:

樂於分享的軟體工程師,曾在新創與大型科技公司實習,獲得黑客松競賽冠軍,擔任資安研討會講者。長期熱衷於資訊安全、雲端服務、網路行銷等領域,希望將科技知識分享給更多人。內容轉載請來信:jlee58tw@gmail.com

發表回應