1 個月內累積破萬使用者:大學科系查詢 LINE 機器人製作分享

筆者今年在準備升學,所以前陣子在翻找大學申請簡章、整理志願標準跟面試日期,後來覺得翻書找好麻煩,便在寒假製作一個可以查詢個人申請、繁星標準的大學科系查詢 LINE 機器人,沒想到公開不到一個月就有一萬位使用者,便在空閒時寫一篇製作筆記,分享我用的語法、資源、遇到的問題與解法,給未來想開發類似聊天機器人的讀者參考。

本文篇幅較長,我主要會分為想出點子的「 想法層面 」,和實際寫 code 的「 技術層面 」,如果你是單純好奇我怎麼想到這點子,或是怎麼抓到同學痛點、設計出破萬使用者的機器人,可以參考第一、第二段。

倘若你想直接看深層技術的開發過程( 包含怎麼寫程式碼 ),可以從第三段開始。當然也可以整篇都慢慢看完啦 XD 那我會很感謝你的閱讀


機器人成果示範 📱

先給大家看一下大學科系查詢 LINE 機器人的操作成果,只要傳送指定大學科系,機器人會回傳該科系的資訊,以及教育部官方的校系分則連結:

點擊加入行事曆,會轉到 Google 行事曆,面試日期、標題資訊都套好了,只需要按儲存:

點選收藏的話,機器人會紀錄起來,傳送「顯示收藏」即可查看之前收藏的科系:

前面加繁星兩個字,則可以查看繁星標準與轉系規定:

是不是很酷?有需要的話,歡迎點選 LINE Bot 連結加入好友,或是輸入 ID : @958pgmas。下文我會解說我製作這機器人的過程。


設計動機:讓找科系變更有效率 🤔

會聯想到用 LINE 找大學科系資訊、製作聊天機器人,主要有 3 個原因:

  • 翻紙本簡章不方便,想更有效率的查找科系資訊
  • 怕選到二階面試日期重疊的科系
  • 想省去另外整理目標科系的時間

想走個人申請的高三學生都會買本幾百頁的個申簡章,包含筆者也有買,去年十二月我翻簡章時就覺得很麻煩,而且輔導老師都會提醒選志願時,要避免挑到面試日期重疊的科系,更重要的是我想節省手動剩下彙整目標科系的過程。

我就一直在思考:有沒有辦法能讓同學找科系更方便

後來我想起我曾經做過一個線上課程預約的 LINE 群組機器人,那就再製作個聊天機器人,讓大家在熟悉的 LINE 上找大學科系資訊!

因為之前有開發 LINE Bot 的經驗,所以我想到也能用 LINE 找科系

發想機器人的特色功能 🤖

在 2021 一月學測考完、開始放寒假後,我就著手設計大學科系查詢 LINE 機器人的 side project,第一步我先發想這機器人要有哪些功能?我從之前發現到的 3 個問題( 動機 )來著手:

  • 省去翻簡章的不便:就讓同學傳要搜尋的科系,機器人回傳該科系的資訊
  • 避免面試日期重疊:幫同學設定面試行事曆
  • 節省整理科系時間:設計收藏科系功能,同學無需另外整理

在設計機器人的功能時,我以「 解決當初觀察到的問題 」為準則,思考有什麼科技方法或工具能增加效率、減少麻煩?能否以自動化的程式取代以往得手動做的事情

例如解決二階日期重疊問題時,我第一個念頭是用電腦、手機上的行事曆設定活動、來看有沒有重疊。

手機行事曆上可以建立活動,也能用來看日期是否有重疊

我在寫程式或教學文章時,常會思考有哪些操作對人們來說是個問題?是否有相對應的程式碼或手段能幫忙?我不是從零開始製作一個工具出來,而是利用環境現有的資源,串接成能解決大家問題的模組成品而已。


如果你也想做有關資訊類的專案或高中自主學習計畫,筆者推薦從上面這些切入點構思。


設計機器人的架構與流程 🔧

想出特色功能後,我接著開始設計機器人的架構和搜尋流程,本段我會說明當時設計架構的思路,和現在我想到的替代方案。

架構設計:Google 全家桶

做查詢資料的 LINE 機器人,開發者需要準備 2 個部分:

  • 雲端主機:負責執行機器人的程式碼
  • 資料庫:儲存要回傳給使用者的大學科系資料

我在做這個 side project 之前,就有計劃找同學一起來參與,我負責程式部分,其他同學幫我彙整科系資料,讓同學也能透過我的專案累積他們的備審資料( 作爲回饋,我也教他們寫基礎程式 )

因此當時我選用 Google 試算表當作小型資料庫,因為它是最普遍、學生都會用的線上文書服務,而且要教同學寫 SQL 編輯資料庫會來不及。

語法部分我則選擇用 Google 開發的 App Script,它是基於 Javasript 的程式語言,內嵌許多 Google 服務 API,其中就包含讀寫 Google 文件、試算表的功能。

App Script 也跟 Google 文件一樣能在線上 IDE 編寫、執行,我就不用另外設定金鑰、串接到自己的 server,結果發現架構變成完全 Serverless 的 Google 全家桶了 XD

架構圖如下:

不過如果很要求效能的話,用真正的 SQL Database 和 GO, Java 語法去做會更好,App Script 本身執行速度,與 Google 試算表的讀寫速度表現並不是很快。

我這裡為了前期編輯的便利性而犧牲了一些效能,但後文我會說明我怎麼改善執行效能的。

搜尋流程

搞定架構設計後,我繼續規劃搜尋流程的部分,意指推演同學用 LINE 機器人查詢科系的操作步驟,我盡量保持簡單:

  1. 使用者傳送大學科系關鍵字
  2. 機器人判斷使用者要找哪個大學科系後,從試算表抓出相對應的科系資料並回傳
  3. 使用者點選搜尋結果的按鈕,看校系分則或建立行事曆

大學科系查詢 LINE 機器人的開發紀錄 💻

OK,準備進到寫 code 的環節了!本段會說明我怎麼把前面發想的功能,以程式碼的方式實踐出來,以及一些寫程式時的思路等等紀錄,程式開發對我而言算是興趣而已,不是電神、職業級的那種水準,還請各位前輩讀者指教!

前期我原本是寫 Python 爬蟲去抓大學甄選入學委員會的校系分則結果,之後發現網路上已經有知名補習業者《 甄戰 》彙整好的資料,所以我的科系 data 取自這兩個來源,不是手動翻紙本收錄,同學彙整資料的同時,我就處理程式的部分。

分析大學跟科系關鍵字( 包含簡稱跟縮寫 )

首先對我而言,最困難的就是分析使用者的關鍵字了,因爲每個科系都有它的縮寫與簡稱,像是資訊工程學系,我們普通都講資工;企業管理學系則是企管⋯⋯要預測使用者的科系搜尋意圖真的很困難。

這就是我請同學來幫忙的主要原因,我請他們針對每個科系去聯想可能的縮寫,並輸入到 Google 試算表裡,真的是「 人工 」智慧分析出來的:

Google 試算表截圖,A 欄位是同學輸入的預測關鍵詞

我預設同學是要搜尋某某大學的某某系,因此訊息一定包含「大學」跟「科系」兩個部分,設計的分析流程如下:

  1. 分析使用者要查哪間大學,跟哪個科系
  2. 先檢查該大學有沒有要搜尋的科系,有的話就回傳資料

那怎麼判斷關鍵字訊息裡哪部分是大學、哪部分是科系呢?我那時用了簡單粗暴的方法,以「 大 」或「 大學 」做分水嶺,前面的是大學名稱,後面就當科系名稱,開啟該大學的工作表,接著比對關鍵字欄位裡有沒有匹配的字詞。

例如台大資工,台大( 大字之前的訊息 )就當作大學,後面的資工就是科系,機器人開啟臺灣大學的工作表,回傳資工那行的科系資訊。

App Script 程式碼實作如下,我忘記留最初用 include 比對的版本,所以先放最新版的( 點我跳過程式碼部分 ):

那這樣會有個問題,假如使用者沒傳「大」字呢?像東海法律、世新廣電?

我剛開始是要求傳訊息一定要包含大字,否則當作無效訊息,後來我使用 Fuzzy Search 模糊搜尋來比對,同時解決科系縮寫的問題,詳細資訊會在下文提到。

我把在試算表撈到的所有資料塞進一個 array,然後再把 array 每七個一組,拆成二維陣列並丟到 Flex Message 的 JSON 裡,回傳給使用者:

補充:
– Flex Message 是 LINE 的新版訊息格式,有較多的外觀自訂選項
– 會拆成 7 個一組是因為我資料庫裡,每個科系的資料只有 7 格。

設計收藏科系功能

再來是收藏功能,我在生成一個 Flex Message 時,在加入收藏的按鈕 postback 放入觸發詞 dash 號 “-” 跟科系名稱,當機器人收到的 postback 含有 dash,就用 split 語法以 dash 把 postback 切成大學代號與科系名稱,後面方法就跟找科系一樣了:

由於收藏資料庫包含使用者們的隱私資訊,這裡不便公開截圖了。

隱私聲明:個人針對收藏資料庫有加強權限管理,只有機器人本身能去讀寫,其他幫忙的同學無法存取,我也只在網友同學回報問題時進去修正,亦不會洩漏使用者儲存的科系給任何人或第三方單位

設計新增行事曆功能

上面有提到:我想藉由建立行事曆的方式,幫同學檢查面試日期是否重疊,但在 LINE 裡面無法存取 iPhone 內建的行事曆,所以我改用 Google 線上行事曆,支援 iOS /Android,安卓手機預設是用 Google Calendar,iOS 上則會開啟網頁版。

有個好處:可以用網址方式建立 Google Calendar 活動

Google Calendar 有個好處是可以透過 url 來稱建立活動,還能改參數來設定時間、標題跟說明,不用設定行事曆 API 去新增,像下面這組 url 是台大資管的:

台大資管的 Google 日曆連結

我就寫一個動態生成行事曆 url 的 function,丟入科系名稱與時間,轉換成可點擊的連結:

p.s 我目前還在整理機器人完整的程式碼,等註解都寫完後,我會把 GitHub 連結公開在這裡。

使用者暴增!加快程式碼的執行速度

結果一月底我公開之後,經過兩次的使用者暴增潮( 一天內增加快 4000 位使用者 )而程式碼無法同步處理大量的查詢訊息,要先傳給 A 結果才會處理 B 的訊息,而且 App Script 的執行速度沒有到很快,於是我後期一直在改善程式碼的執行速度。

這裡我分享 3 個我改善 Google App Script 執行速度的方法:

  1. 多使用內建語法
  2. 使用快取,暫存要回傳的科系結果
  3. 在 postback 加入欄位數值,省去比對時間

使用內建語法

以往我檢查一個 Array 裡有沒有包含一個值,都是用 loop 檢查:

function contain_6_loop(){

    let test_array = [1,2,3,4,5,6,7,8];
    let time = test_array.length;

    for(let x = 0; x < time ; x++ ){
        if(test_array[x]==6){
            return True;
        }
        return False;
    }
}

console.log(contain_6_loop()) // True

後來為了加速程式碼執行速度,我研究一下,發現改用內建語法可以減少執行時間,像是可以改用 .some 來檢查,大幅改用內建語法後,程式的執行速度確實有變快一些:

let test_array = [1,2,3,4,5,6,7,8]:
let contain_6 = test_array.some(data => data.includes(6));

console.log(contain_6) // True

啟用快取

機器人在搜尋科系時,會頻繁的讀取試算表的資料,這樣也會花一段時間,後來我也發現 App Script 有支援快取( 不是收銀 )

快取是常被重複使用或運算,而暫存下來的資料,以我的 case 來說,假設同學 A 傳「 台大資工 」,機器人找到並回傳台大資工的訊息 JSON 後,就把這筆結果存為快取,之後同學 B 傳台大資工時,機器人就傳上次快取的訊息,不用再從頭搜尋試算表。

因為我要傳的內容不具有即時性,所以我用快取來減少搜尋資料庫的動作。倘若你要傳的內容常即時更新,像車次或虛擬貨幣價格,就建議縮短快取時效,或乾脆不要用快取以免撈到過期資料。

收藏 Postback 加入欄位值

以往使用者要看收藏科系時,機器人都得不斷在資料庫檢索目標科系在工作表裡哪一行,再抓取該行的科系資料,但收藏科系很多時,就要等很久才會叫出結果。

我就想到同學收藏科系之前就會搜尋科系,而在搜尋科系的同時機器人就會檢索資料庫了,那就在搜尋時紀錄下該科系在哪一行,這樣顯示收藏時就直接抓那行的資料,原本的 postback 如下:

ntu-國立臺灣大學資訊工程學系
// Bot 會分成 "ntu" 和 "國立臺灣大學資訊工程學系",接著比對

後來我就在 postback 裡面多塞一個目標行數:

ntu-27-國立臺灣大學資訊工程學系
// Bot 直接讀取 "ntu" 工作表第 27 行的資料,省去比對時間

修改後效果顯著,顯示結果的時間從 8 秒變到 3 秒左右( 在 IDE 端編譯的數據 )

以下是我在改善程式碼執行速度時,參考的網路資源:

開發遇到的問題與解法

抓半天還找不到 bug 的我,上圖為示意圖 XD

接著分享一下我在開發大學科系查詢 LINE 機器人遇到的瓶頸問題,還有後來的解法。

縮寫太多種?改用模糊搜尋( Fuzzy Search )

儘管前期我請同學幫忙新增縮寫關鍵字,但難以涵蓋同學、家長用的縮寫,因此我研究怎麼把第三方的 Fuzzy Search 模組套用到 App Script 裡。

Fuzzy Search ( 模糊搜尋 )跟用 include 比對的差別在於:前者不用完全匹配才會判定為包含,假設我要判斷資工是否為資訊工程學系,include 完全匹配的結果如下:

var dp = "資工", target = "資訊工程學系"

if(target.include(dp)){
    console.log("包含!")
}
else{
    console.log("不包含")
}

// 會顯示不包含,因為 target 裡面沒有資工這個字詞

如果改用模糊搜尋就不一樣了,因爲資訊工程學系裡有資、工這兩個字,系統就能判斷為包含。

我是用 Fuse.js 這個模組來做模糊搜尋的,它載入不錯,回傳也會給予各個 value 的相似度( score )所以我會依照 score 的大小來判斷是否匹配。

Google App Script 不支援 npm install 外部模組,必須用 CDN 連結方式載入

Request 用量超額:一樣用快取暫存

之前載入 Fuse.js 時,我是設定每搜尋一次,就從 CDN request 載入一次檔案,而 App Script 第三方 request ( UrlFetch )是有用量限制的。結果後來人數暴增時,一天內就超標了,剛學會用 cache 的我才想起來:可以快取起來,這樣未來就不用頻繁 send request 了:


在本次作品學到的事

在做「 大學科系查詢 LINE 機器人 」這個 side project 時,由於使用者遠遠傳出我的預期,我寒假花超大量的時間跟心力去製作跟維護,也學到很多部分:

  1. 將程式碼模組化,並利用 try catch 抓錯誤,所以 debug 時省很多時間
  2. 幫程式碼做最佳化,提升執行速度
  3. 蒐集使用者回饋意見,改善並新增功能
開發過程中,不斷根據同學的意見私訊去做調整與改善機器人

我有在機器人回覆訊息裡放我的工作用 email,所以陸陸續續有收到一些同學的建議與功能許願,像是有不少同學反應想加入繁星標準,我就另外寫查繁星的功能,希望讓這個成品更貼合同學和家長的需求。

技術總結

能開發出「 大學科系查詢 LINE 機器人 」真的是很特別的經驗,這是我第一次自己建立這麼多使用者的成品,在三個禮拜多內使用者就能破萬,不僅多累積了一個程式作品,我還因此受邀參加 LINE Developers 線上小聚,更重要的是我得以實踐去年的初衷,幫同學找科系更方便了。

真的沒想到會有破萬使用者的一天

說實話,看到使用者飆升、跟持續收到私訊意見難免有點壓力,但現在來看算是很有成就感,從想出 idea、找同學整理資料、寫程式碼….自己走完一次開發程式的路,感觸許多。

此外這個機器人發布後,也有被其他開發者和部分品牌「 致敬 」,市面開始出現類似功能的 LINE Bot。現在的我其實很高興,因為我的初衷就是「 幫高中同學和學弟妹更方便找科系資料 」

哪怕別人借鑒我用 LINE 查大學科系標準的點子、製作類似的服務,對整體學生族群來說都是有利的,查科系申請資料不再是難事,所以致敬者也是間接幫我達成目標了,感謝他們的幫忙 XD

圖為我之前收到的意見回饋 Email

感謝你的閱讀!希望能幫到你開發 LINE 機器人或自己的資訊專案。如果你對我的開發歷程發表看法,或想給程式方面的建議,歡迎在本文下方留言,或是透過「與我聯絡」的表單也可以!

大學科系查詢機器人好友連結 👈🏻
機器人 IG 帳號( 第一時間通知新功能上線 )👈🏻

開發 LINE 機器人的參考資料

以下是我在開發過程參考的重點網路資源:

延伸閱讀

做個 LINE 機器人記錄誰 +1!群組 LINE Bot 製作教學與分享

LINE Bot 機器人實作
發佈留言

發佈留言必須填寫的電子郵件地址不會公開。

前一篇文章

【個人年度回顧】2021 年 5 件我學到最重要的事情

下一篇文章
大學個人申請二階備審封面,包含學習歷程自述與多元表現心得

學習歷程自述、多元表現綜整心得怎麼寫?6 項大學二階備審整理懶人包