iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 5
2
Modern Web

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

Day 05:串接 API,讓 Chatbot 不是只能講幹話

上一篇有教到如何讓機器人講出隨機的一則笑話,但如果都只是讓機器人講講笑話講講幹話,這讓工程師要怎麼能取得成就感?
而且 AI 也是能講幹話的,它在網路上看來看去,收集的梗可能比你還多,未來講幹話要講贏 AI 基本上沒可能,所以總是要能做一些門檻高一點的事情你說是吧。

今天要試著來接一個 HTTP API (Application Programming Interface),簡單來說,就是藉由去另一個網站服務拿資料,來呈現在 Chatbot 裡面。

我在一個專門收集公開 API 的 GitHub Repo - Public APIs 裡面找了一個文件不錯、而且不需要註冊、登入、API key 就能使用的 API 來在這邊使用,是專門用來查詢 Cryptocurrency (加密貨幣)的 API,所以今天要來做個 Cryptocurrency 的 Bot,文件如下:

https://docs.coinranking.com/public

(注意:這邊請一樣從「Day 02:Bot 開發起手式」中所教學的架構開始動手做)

建立 API Client

首先,我們必須先搞定透過 HTTP 取得資料的部分,方便之後可以在 Bot 裡面去呼叫。

找了一下,查詢 Coin 的資料的 API,文件如下

https://ithelp.ithome.com.tw/upload/images/20190920/20103630qG8nhmPaXa.png

(出自:https://docs.coinranking.com/public#getcoin)

根據 Request URL - https://api.coinranking.com/v1/public/coin/:coin,我們可以這樣來寫我們的 Cryptocurrency 的 API Client:

// 這檔案存成 coinranking.js
const axios = require('axios'); // 記得要 npm install axios

const client = axios.create({
  baseURL: 'https://api.coinranking.com/v1/public/',
});

module.exports = {
  async getCoin(coinId) {
    const response = await client.get(`/coin/${coinId}`, {
      params: {
        base: 'TWD',
      },
    });
    
    return response.data;
  },
};

(如果不太懂的讀者可以先直接照抄就好)

我習慣用 axios 這個套件來發送 HTTP Request,如果有其他偏好也可以使用其它 HTTP 套件替代,不然就跟著使用 axios 即可,這邊 baseURLhttps://api.coinranking.com/v1/public/,path 為 /coin/:coin,method 為 get

至於為什麼要把 base 參數傳進去 params 呢?因為我想要用新台幣當 base (預設是美金),那必須讓它最後網址上有帶 base=TWD

另外為了簡化並更容易講解重點,我接下來範例中只會使用三個常見的 Cryptocurrency,這邊列舉放在陣列裡,BTC (比特幣)、ETH (以太幣) 跟 XRP (瑞波幣):

const coins = [
  {
    id: 1,
    symbol: 'BTC',
    name: 'Bitcoin',
  },
  {
    id: 2,
    symbol: 'ETH',
    name: 'Ethereum',
  },
  {
    id: 3,
    symbol: 'XRP',
    name: 'XRP',
  },
];

完成 Cryptocurrency 查詢

首先我們先來看看怎麼利用剛剛完成的 coinranking.js 來把比特幣價格查出來,記得最上方要用 require 把剛寫好的檔案載進來當作 module:

// index.js
const coinranking = require('./coinranking'); // 還記得我們上面寫的 coinranking.js 吧

module.exports = async function App(context) {
  const { text } = context.event;
  if (/(btc)|(bitcoin)/i.test(text)) {
    const {
      data: { coin },
    } = await coinranking.getCoin(1);
    await context.sendText(`BTC 現在價格是 ${coin.price} TWD`);
  }
};

/(btc)|(bitcoin)/i.test(text) 這是正規表達式的用法,可以用來判斷字串是否符合特定的規則,如果不太熟悉可以看看 MDN 上的介紹(i flag 是不分大小寫,所以這可以判斷符合 btc、bitcoin 的字串而且不分大小寫)。

coinranking.getCoin(1) 會回傳這樣的資料:

{ 
  status: 'success',
  data: { 
    base: { symbol: 'USD', sign: null },
    coin: { 
      id: 1,
      price: '347052.9099999797',

      // ... 其實還有很多資料顯示方便先省略
    },
  },
}

實際使用起來是這個樣子:

https://ithelp.ithome.com.tw/upload/images/20190920/20103630PctRIhwSMW.png

使用了基本的正規表達式後,無論大小寫、前後加上怎樣的文字都能命中,這在之後可以改用更嚴謹的判斷或是使用 AI、Machine Learning 相關的技術和服務來輔助判斷。

到目前為止這樣就很不錯啦,已經能達到基本要求,運用動態的 API 資料來完成這個對話。到這邊已經離今天的目標無限接近了,最後我們來試著把前面提到的陣列(包括比特幣、以太幣跟瑞波幣的那個)拿出來用,把在程式上寫死的東西變得更少,並完成能任意查詢三種貨幣的目標!

// index.js
const coinranking = require('./coinranking'); // 還記得我們上面寫的 coinranking.js 吧

const coins = [
  {
    id: 1,
    symbol: 'BTC',
    name: 'Bitcoin',
  },
  {
    id: 2,
    symbol: 'ETH',
    name: 'Ethereum',
  },
  {
    id: 3,
    symbol: 'XRP',
    name: 'XRP',
  },
];

module.exports = async function App(context) {
  const { text } = context.event;
  for (let c of coins) {
    if (new RegExp(`(${c.symbol})|(${c.name})`, 'i').test(text)) {
      const {
        data: { coin },
      } = await coinranking.getCoin(c.id);
      await context.sendText(`${c.symbol} 現在價格是 ${coin.price} TWD`);
      return;
    }
  }
};

這邊稍微複雜的是使用了 for...of 語法來迭代陣列,還有改用 new RegExp 的寫法來動態產生正規表達式,但除此之外都只是把前面的範例帶入變數而已哦。

大功告成!最後這樣感覺已經很好了,已經能說是做出了一個實用的機器人了!

https://ithelp.ithome.com.tw/upload/images/20190920/20103630Qy5Lux9eIY.png

結語

經過這樣一篇下來,大家應該已經能感覺到,只要能夠串接各種 API,Bot 就無所不能。不管是要查天氣、訂飲料、關電燈還是網購,都不會是什麼大問題。


上一篇
Day 04:Console Mode 還能怎麼玩,開發與 Debug 技巧
下一篇
Day 06:把前幾天的聊天機器人都搬上 Messenger
系列文
使用 Modern Web 技術來打造 Chat App30

1 則留言

1
NiJia
iT邦新手 5 級 ‧ 2019-10-08 15:36:38

public API 那個太讚了!

我要留言

立即登入留言