iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 19
1
Modern Web

使用 Modern Web 技術來打造 Chat App系列 第 19

Day 19:使用「Router」來做功能分流

  • 分享至 

  • twitterImage
  •  

在開發網頁時,我們會用網址來分辨並導向不同的功能,例如用現在最常見的 RESTful 風格來表示網址,因此基本上大部分的伺服器端框架都是使用 HTTP 的 Method、Path 來做 Routing,實現基本的功能切分。

而在機器人的架構上其實也會有類似的概念,我們需要分辨、判斷使用者送出的訊息或造成的事件並導向對應的處理方式。雖然 Conversational Interface 的辨別不會像網址那麼簡單,但不管我們是使用關鍵字、正規表達式抑或是用了機器學習的方式來辨別意圖,這依然都有 Routing 的概念在裡面。

接著,讓我們來看看要怎麼使用「Router」吧!

(注意:這篇文章需要使用最新的版本,可以用 npm update bottender 或是 yarn upgrade bottender 來做升級)

Text Route

首先我們先來處理文字方面的事情,畢竟文字就是聊天機器人的精髓,是最大宗會出現的事件,所以也是最重要的。可以從 bottender/router 去取用 routertext 兩個 function 來定義 Routing 規則:

// index.js
const { router, text } = require('bottender/router');

async function SayHi(context) {
  await context.sendText('Hi');
}

const Router = router([
  text('hi', SayHi),
]);

module.exports = function App() {
  return Router;
};

當我們用字串當作第一個參數時,代表一定要輸入一模一樣的文字才會命中,並採用 Hi 回傳回去:

text('hi', SayHi)

當有多種句法時,可以傳一個字串的陣列進去:

text(['hi', 'hello'], SayHi)

或是要更細緻的規則時,也可以使用正規表達式:

text(/(hi|hello|hey)/i, SayHi)

* 當第一個參數,則可以處理其他前面沒命中的任何文字訊息:

const { router, text } = require('bottender/router');

async function SayHi(context) {
  await context.sendText('Hi');
}

async function FallbackResponse(context) {
  await context.sendText('你不是在打招呼吧');
}

const Router = router([
  text(/(hi|hello|hey)/i, SayHi),
  text('*', FallbackResponse),
]);

所以這邊講出不是「hi」、「hello」、「hey」的文字就會回覆「你不是在打招呼吧」。

Payload Route

文字以外的第二大宗,應該就是 Payload,用法跟 text 幾乎一樣,例如我們想要處理 GET_STARTED 的 Payload 可以這樣寫:

const { router, payload } = require('bottender/router');

async function SayHi(context) {
  await context.sendText('Hi');
}

const Router = router([
  payload('GET_STARTED', SayHi),
]);

更彈性的 Route

當然除了文字跟 Payload 外,你可能還有千千萬萬種理由會想依照 Context 去做分流,那這時候可以用 route

const { router, route } = require('bottender/router');

async function SayHi(context) {
  await context.sendText('Hi');
}

async function FallbackResponse(context) {
  await context.send('你是不是做了些什麼?');
}

const Router = router([
  route(
    context => context.event.isText 
      && context.event.text.startsWith('h'), 
    SayHi
  ),
  route('*', FallbackResponse),
]);

第一個參數的 Function 或 Async Function 只要回傳 true 就算命中,false 就等同沒中。而 route('*', /* ... */) 則是會命中所有的事件,即便是文字、Payload 以外的也都會中。

結語

Router 的使用非常彈性,可以在任意階層使用,也可以在 Router 裡面的某個 Action 裡面再放一個 Router,在設計 Router 的層級對於整個 App 的了解非常有幫助。未來我們會看到使用機器學習的東西又是如何應用 Router 的概念。


上一篇
Day 18:「Composition」- 組合的奧秘
下一篇
Day 20:責任鏈模式 - 「Chain」的思考
系列文
使用 Modern Web 技術來打造 Chat App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言