IBM BluemixとNode.jsでお天気通知!―Facebook Messenger Bot(4) / Facebook Messanger Botをデプロイ

AWSやAzureを始めたとしたクラウドサービス全般を触っていく連載「クラウドサービス研究スタジオ」。この連載では、IaaS,PaaS,BaaS,SaaSなど幅広い形態のサービスを実際に使ってレポートしていきます!

今回作るもの

こんにちは、エンジニアのちゃんとくです。テクニカルライターとしてdotstudioに参加しています。

今回は、2016年に公開された話題のMessenger Platformを使ってFacebook Messenger Botを作りIBM Bluemixにホスティングしてみます。

下記のようにお天気を教えてくれるものを想定しています。

BotプログラムはNode.jsで作成し、IBM Bluemixで提供されているWeather Company Dataから天気情報を取得してIBM Bluemixにホスティングし運用します。

下記の構成で手順を紹介します。

  • IBM Bluemixの設定
  • Botのベースを作成
  • 天気情報を取得
  • Facebook Messenger Botをデプロイ

今回は第2回で作成したFacebook Messanger Botのベースと3本目で作成した天気情報取得のプログラムを組み合わせ、いよいよBotのデプロイまでやってみましょう!

筆者の環境

OS X El Capitan(v10.11.6)
Node.js v8.2.1

8,568通り、あなたはどのタイプ?

天気を返すBotプログラムを作成する

app.jsは以下のように変更します。トークンや認証情報はBluemix上の環境変数から取得できるようにしておきます。

'use strict;'

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();

// facebookの設定
const my_token = process.env.MY_TOKEN;
const access_token = process.env.ACCESS_TOKEN;

// weather apiの設定
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
const LONGITUDE = '35.698353';
const LATITUDE = '139.773114';
const BASE_PATH = `https://${username}:${password}@twcservice.au-syd.mybluemix.net/api/weather/v1/geocode/${LONGITUDE}/${LATITUDE}/forecast/daily/3day.json?language=ja-JP`;

/**
 * 天気データを取得
 */
const getWeatherForecast = () => {
  return new Promise((resolve, reject) => {
    request({
      url: BASE_PATH,
      method: 'GET'
    }, (e, res, body) => {
      if (!e && res.statusCode == 200) {
        resolve(body);
      } else {
        reject(`Error: ${body}`);
      }
    });
  });
}

/**
 * いつの予報を返すか判定
 * @param {string} text
 * @return {number}
 */
const getForecastDay = (text) => {
  const day = {'今日': 0, '明日': 1,  '明後日': 2, '明々後日': 3};
  return day[text];
}

/**
 * @param {res} data
 * @param {number} day
 * @return {string}
 */
const dataToMessage = (res, day) => {
  return res.forecasts[day].narrative;
}

const sendTextMessage = (sender, text) => {
  const messageData = {
    text:text
  }
  request({
    url: 'https://graph.facebook.com/v2.6/me/messages',
    qs: {access_token:access_token},
    method: 'POST',
    json: {
      recipient: {id:sender},
      message: messageData,
    }
  }, (error, response, body) => {
    if (error) {
      console.log('Error: ', error);
    } else if (response.body.error) {
      console.log('Error: ', response.body.error);
    }
  });
}

app.set('port', (process.env.PORT || 3000));

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.get('/', (req, res) => {
    res.send('Hello, Facebook Messenger Bot.');
});

app.get('/webhook', (req, res) => {
    if (req.query['hub.verify_token'] === my_token) {
      res.send(req.query['hub.challenge']);
    }
  res.send('Error, wrong validation token');
});

app.post('/webhook', async (req, res) => {
  let messaging_events = req.body.entry[0].messaging
  for (let i = 0; i < messaging_events.length; i++) {
    let event = req.body.entry[0].messaging[i]
    let sender = event.sender.id
    if (!event.message || !event.message.text) return;

    let forecastDay = await getForecastDay(event.message.text);
    let message;
    if (forecastDay === undefined) {
      message = 'いつの天気を知りたいですか?';
    } else {
      let res = await getWeatherForecast();
      message = await dataToMessage(JSON.parse(res), forecastDay);
    }
    sendTextMessage(sender, message.substring(0, 200));
  }
  res.sendStatus(200);
});

app.listen(app.get('port'), () =>
  console.log('running on port', app.get('port'))
);

Bluemixで動作するよう、いくつか設定を追加します。package.jsonは以下のようにします。上記のコード内で使用したasync/awaitはv7.6から利用できるのでバージョンを指定しておきます。

{
  "name": "chantoku-bot",
  "main": "app.js",
  "private": false,
  "engines": {
    "node": "7.6.*"
  },
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "body-parser": "^1.17.2",
    "express": "^4.15.4",
    "request": "^2.81.0"
  }
}

起動スクリプトやエンジンの指定などが必要です。利用するモジュールも全て記載されていることを確認してください。

manifest.ymlを作成し、以下のようにアプリケーション名を記述します。

---
applications:
 - name:chantoku-bot
   random-route: true
   memory: 256M

.cfignoreを作成しデプロイしないファイルを記述します。

node_modules/
*.DS_Store
README.md
.github/
.git/
.gitignore
logs
*.log

cf pushコマンドでデプロイします。

8,568通り、あなたはどのタイプ?

Bluemixに環境変数を設定

tokenを環境変数で受け取れるようにBluemix上で設定しておきましょう。アプリケーションの「ランタイム」の「環境変数」の項目に移動します。

「追加」から新しい項目を追加し、MY_TOKENACCESS_TOKENUSERNAMEPASSWORDをそれぞれ設定して「保存」で完了します。「MY_TOKEN」はFacebook側の認証用に任意の文字列を設定しておきましょう。

Facebook Messangerでwebhookを変更する

Facebook Messangerの設定画面からBot用の設定を追加していきましょう。

2本目ngrokというトンネリングツールを使ってローカルでBotを試しましたが、作成するBluemixアプリケーションのパスを利用するように変更します。「Webhooks」ページの「Edit Subscription」を選択します。

コールバックURLにはBluemixアプリケーションのパス+/webhookを指定し、トークンには環境変数のMY_TOKENに設定した任意の文字列を指定します。

「確認して保存」で設定は完了です。

callbackが正しく返ってくると登録できます。登録できない場合は任意の文字列が一致しているか、デプロイが完了しているかなどを確認しましょう。

試してみます!

Botを試してみる

Facebook Messangerから話しかけてみます。

お天気を返してくれるBotが完成しました!

ちなみにBotを公開して稼働させるにはFacebook公式の審査が必要です。詳細はガイドを参照してください。

まとめ

4回かけてNode.jsでFacebook Messanger Botを作成しました。Bluemixへホスティングしたアプリケーションと天気データ取得サービスを簡単に連携することが出来たと思います。

Botプログラムは会話を解析したり情報を取得して返したりすることが多いので、特にBluemixと相性がいいかもしれません。

引き続き、様々な形態に適した便利なクラウドサービスを紹介していきたいと思います。

それでは!

取材・執筆:dotstudio, inc. ちゃんとく

大学までは文系で法学を学んでいたが「モノを作れる人」に憧れて知識ゼロからWebエンジニアの道へ。転職し現在はIoT中心のエンジニア・テクニカルライターとして活動。Node.jsユーザグループ内の女性コミュニティ「Node Girls」を主催。Twitter: @tokutoku393 / dotstudio, inc.

※本記事は「CodeIQ MAGAZINE」掲載の記事を転載しております。

PC_goodpoint_banner2

Pagetop