上一篇有教到如何讓機器人講出隨機的一則笑話,但如果都只是讓機器人講講笑話講講幹話,這讓工程師要怎麼能取得成就感?
而且 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 開發起手式」中所教學的架構開始動手做)
首先,我們必須先搞定透過 HTTP 取得資料的部分,方便之後可以在 Bot 裡面去呼叫。
找了一下,查詢 Coin 的資料的 API,文件如下
(出自: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
即可,這邊 baseURL
為 https://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',
},
];
首先我們先來看看怎麼利用剛剛完成的 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',
// ... 其實還有很多資料顯示方便先省略
},
},
}
實際使用起來是這個樣子:
使用了基本的正規表達式後,無論大小寫、前後加上怎樣的文字都能命中,這在之後可以改用更嚴謹的判斷或是使用 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
的寫法來動態產生正規表達式,但除此之外都只是把前面的範例帶入變數而已哦。
大功告成!最後這樣感覺已經很好了,已經能說是做出了一個實用的機器人了!
經過這樣一篇下來,大家應該已經能感覺到,只要能夠串接各種 API,Bot 就無所不能。不管是要查天氣、訂飲料、關電燈還是網購,都不會是什麼大問題。