兩小時打造簡單 Line Chatbot — 使用 Google Apps Script & Google Sheet API
聊天機器人從前一陣子開始很紅,幾乎可以看到很多商家粉絲頁或是 Line 帳號,都用 chatbot 來減少人力成本快速回覆,或是更近一步可以搭配 AI 做更多事情。之前一直就想要試玩看看 bot,這次就拿 line bot 來自己練習,並且當做個範例,快速建置一個簡單(沒什麼功能)的機器人。
這次用我們的調酒小專案來當作主題,建立一個可以透過調酒名稱來查詢調酒故事,照片與更多資訊連結的 chatbot。
調酒小專案 Over Party Lab
由幾個工程師們建立的調酒頻道,分享創作理念與經典調酒,歡迎參觀。
環境
這次會選擇 google apps script 是因為他能夠達到快速建立一個後端 service 的目標,不需要做太多複雜的設定,寫完直接 deploy 就可以馬上使用。
在儲存資料方面,之前用 google 服務我都會選擇搭配使用 firebase,可是後來發現如果只是單純存取資料,用 Google sheet 來當一個類資料庫,意外的快速方便。當然這是不考慮效能或是大量使用的情況下,如果只是做個簡單 POC 或輕量級使用,用 Google sheet 充當資料庫就很夠用了。
申請 line 帳號
在開始之前,要去 Line Developers 申請一個 Line Messaging API 的帳號
登入之後去 Create 一個新的 Provider,一個 Provider 可以有多個不同的 Channel,要選擇建立一個新的 Messaging API Channel。
建立完之後,要做一些簡單的基本設定,像是名稱,圖片,email …等等。到這步之後,基本上只會回 default message 的 line chatbot 就已經建好了,底下有 QRcode 可以加入去測試看看。
再來記得要去 Channel information 做一些帳號設定。
- Response mode: 決定這個帳號要是 bot 還是人工回覆 (chat)
- Greeting message: 加入帳號的歡迎訊息,可以按 settings 進去做設定
- Auto-response: 對於 user 訊息的自動回覆,如果是要當做 bot 使用,要把這個設定關掉
- Webhooks: 這個要打開等著之後跟 google app script 溝通
到這裡 line bot 的基本設定就做好了,再來就要進入 Google apps script & Google sheet API 了。
Google Sheet API
在講 apps script 之前,先來準備我們需要的類資料庫 — Google Sheet。
使用上就是把每一張 sheet 當作 Relational Database 的 Table 來設計就好了,至於要設計到多複雜或是正規劃等等就看各人喜好了。
最重要的是,要把共用打開,並且記下這張 sheet 的 key (SHEET_ID)。
你的 key 就會是網址中間那段。
https://docs.google.com/spreadsheets/d/{SHEET_ID}/edit#gid=0
到這裡,Google Sheet 的部分就算是完成了。
Google Apps Script
Google Apps Script 是 Google 推出基於 JavaScript 的一個服務,他可以很輕易的結合 Google 的其他服務,並且到目前為止都還是免費使用。不過免費的有些配額限制,可以到官方文件來查閱 (Quotas for Google Services)。雖然有配額限制,但拿來做 POC 或是自己的小玩具很夠用了。
建立一個 Script
要建立一個 Script 非常容易,只要開啟 Google drive 雲端硬碟,就可以直接新增建立了。
打開後會長這樣,副檔名都是 .gs,可惜的是撰寫的語法要使用 JavaScript ES5 之前的語法,使用 ES6 的話會直接噴錯,寫起來會有點不太順手。
如果真的覺得 ES5 寫不下去,還是可以使用 Google 推薦的另一個套件 clasp,可以下載到 local 來寫,可以使用 Typescript 來寫,push code 會自動轉成 .gs file。
Update: 現在 Google Apps Script 已經可以使用 ES6 以上寫法囉
新版 Google Apps Script 使用教學:
更多使用 clasp 開發請看:
到這裡第一步準備的工作就大致完成了,順利的話應該不用 15 分鐘就可以搞定。
連接 Google Sheet API
由於 Apps Script 內建就有很多 Google Service 的 API 了,Google Sheet 也是其中之一,因此只要直接使用就可以了。
使用 Google Sheet 就很像使用 Database 一樣,首先要先連上 SpreadSheet (DB),再決定你要用哪一張的 Sheet (table)。
Connect to SpreadSheet
使用剛剛從 Google sheet 連結中拿到的 key 來當作 SHEET_ID
var spreadSheet = SpreadsheetApp.openById(SHEET_ID);
接著使用 spreadSheet instance ,透過 SHEET_NAME 來存取內部的 sheets
var sheetInstance = spreadSheet.getSheetByName(SHEET_NAME);
就能使用這個 sheet 來做新增,刪除等等的動作了。唯一麻煩的地方,可能就是不能下 SQL 。
雖然 Google Sheet 有 query function 可以使用,使用起來跟下 SQL 一樣十分方便,但目前 Google Sheet API v4 看起來是沒有 enable 這個功能,所以要自己想辦法用 JavaScript 邏輯來做 CRUD 的存取。
The Sheets API v4 does not currently have a direct equivalent for the Sheets API v3 structured queries. However, you can retrieve the relevant data and sort through it as needed in your application.
常用的 API
在這次專案中,我只有用到讀取與寫入簡單的 API
- 讀取資料
使用getSheetValues
可以從指定的 sheet 拿出資料的範圍
/**
* @param {number} startRow 開始 row 的位置
* @param {number} startColumn 開始 column 的位置
* @param {number} numRows 目標要抓多少 row 數量
* @param {number} numColumns 目標要抓多少 column 數量
* @return {Object[][]}
*/
sheetInstance.getSheetValues(
startRow,
startColumn,
numRows,
numColumns
);
- 抓出有資料的最後一個 row
使用 getSheetValues
來抓出目前 sheet 中,最後一列 row 的 index
/**
* @return {number}
*/
sheetInstance.getLastRow();
- 寫入資料範圍
使用 getRange 搭配 setValues,就可以達到類似 INSERT INTO 的功能了,舉例來說,我想要在 table 第一個 row 依序塞入 4 個值,如以下所示:
var range = sheet.getRange('TEST_TABLE!A1:D1');
range.setValues([[index, search, user, time]]);
這樣就會在 TEST_TABLE 這張 sheet 的 A1 ~ D1 依序塞入 index, search, user, time 四個值了,只要把這個抽出來包裝好,就可以成為一個簡單的 INSERT INTO function了。
- 更多 API
至於詳細還有哪些功能和 API 可以使用,就直接看文件最清楚了。
Google Sheet API Document: Google Sheet API v4
連接 Line Messaging API
最後一步就是要跟 chatbot 做連接了
Deploy Apps Script
在實作完 Apps Script 的內容邏輯後,必須要部署才能夠在網路上存取。
工具列 > 發布 > 部署為網路應用程式
- 專案版本:新增
- 權限:任何人,甚至匿名使用者
這時候,最上面的網址就是你這個應用程式的 API 位置
Line Messaging API 設定
接著回到 Line Developers 你的 Line Messaging API 頁面,往下找到 Messaging settings 這個 section。
- Channel access token: 這是你的這隻 Line Messaging API 的金鑰,按下 Issue 就會建立一組新的,要把這組放到 Google Apps Script 裡面用來與 chatbot 溝通。(後面會提到)
- Use webhooks:是否要使用 webhooks,要選擇 enabled 來開啟。
- Webhook URL:這是 webhook 的位置,把剛剛 Google Apps Script 部署完產生的那組位置貼在這裡,然後按 Verify 去測試一下。
- Allow the bot to join group chats:這個選項視各人情況而定。
在 Google Apps Script 與 Line API 溝通
最後就是要在 Google Apps Script 中跟 Line API 做溝通了
Google Apps Script 中有兩個預設的 HTTP 方法,GET 和 POST。在 Google Apps Script 接收 line 訊息,都會經由 POST 而來,所以我們要先定義一個 POST 的 function。
function doPost(e) {
}
以下是 Webhook event objects format,從這個 object 中,當你收到使用者訊息的時候,就可以相對應作出反應了。
{
"destination": "xxxxxxxxxx",
"events": [
{
"replyToken": "0f3779fba3b3.....",
"type": "message",
"timestamp": 1462629479859,
"source": {
"type": "user",
"userId": "U4af4980629..."
},
"message": {
"id": "325708",
"type": "text",
"text": "Hello, world"
}
},
{
"replyToken": "8cf9239d56244f....",
"type": "follow",
"timestamp": 1462629479859,
"source": {
"type": "user",
"userId": "U4af4980629..."
}
}
]
}
根據這個結構,如果只是單純回話,只需要拿 replyToken 或是 userId ,就可以針對送出訊息的使用者來回覆。
function doPost(e) {
var msg = JSON.parse(e.postData.contents);
var events = msg.events[0];
if (events) {
var replyToken = events.replyToken;
var userMessage = events.message.text;
var userId = events.source && events.source.userId;
}
}
當做完邏輯處理,決定好要回復內容之後,我們要使用 Apps Script 內建的 Fetch API 來回覆訊息。
var payload = {
to: userId,
messages: [{
'type': 'text',
'text': '要回覆的文字訊息'
}]
};var option = {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN
},
'method': 'post',
'payload': JSON.stringify(payload)
};
UrlFetchApp.fetch(
'https://api.line.me/v2/bot/message/push',
option
);
1) payload: 可以使用兩種不同的屬性
- to: userId
- replyToken: replyToken
2) CHANNEL_ACCESS_TOKEN 是剛剛從 Line Messaging API 拿到的金鑰
3) message type 除了 text 其實還有很多中不同格式,像是圖片,影片甚至是問題等等的,可以到官方文件去查詢想要用的 type。
https://developers.line.biz/en/reference/messaging-api/#message-event
小結
一路做到這裡,就可以成功完成一個搭配簡易資料庫,又可以簡單回話的 (不聰明) chatbot 了!再來要怎麼讓 chatbot 更聰明,搭配精準的 rule 或是自動學習,就又是另一段路了。
最後附上 github 連結,有興趣的人可以參考
如果你覺得這篇文章對你有幫助,歡迎買杯咖啡贊助 ☕️ 謝謝