aws serverlessでfacebook messenger botを試してみた
前回のポストから時間がだいぶ空いてしまった...反省。やったことと言えば件名にあることくらいです。まだ中途半端ですが忘れてしまうのでとりあえずメモします。
作ろうと思っているもの
今学んでいるBLOF理論や植物生理、微生物、土の性質、etc...農作物の生産に関するQ&A botができれば便利かなぁと思って着手し始めました。
想定する使い方はいたってシンプルで、
というもの。
ゆくゆくは個別の圃場情報を予めinputしておいて、例えば「A圃場に必要な肥料は?」とか聞くと、「はい、次の施肥をしてください:① バーク堆肥を250kg、アミノ酸肥料を10kg、鉄肥料を2kg、マンガン肥料を1kg を混ぜて施肥してください ② 酵母菌を30g、砂糖を400g、水を5Lを混ぜて施肥してください、③ 1,2完了後、透明マルチを被せて3日間養生してください」とかそういう答えが返ってくるようなものができれば便利だなぁと思ったりします。つまりは圃場メンテナンスにかけるルーチンプロセスを少しでも省略化することができれば便利だなぁと。
利用サービス
作り方
http://docs.serverless.com/v0.5.0/docsdocs.serverless.com
※ wit.aiについては一端スルー(理由は以下)
現状
頭悪くてwit.aiの使い方/メリットがいまいち理解できず...モチベーションが下がり気味です。"音声認識"がついていること以外、単純にスプレッドシートにキーワードとそのキーワードが含まれていた場合の回答を用意しておくのと何が違うのかイマイチ理解出来ていません...。あと自分がバカなんだとおもいますがwit.ai上の単語の意図するところやインタフェースがわかりにくくてイマイチ手が進まないという。
なので、現状はmessengerでテキストを入力するとオウム返しするbotといういたっておもしろみのないサンプルで止まっています。
作る上での方針
今回利用するツールはどれも新しい技術らしく、公式ドキュメント、qiita記事などの第三者情報、どちらか一方にしか無い情報があるということがネットサーフィンでわかりました。ので、「ベースの手順は公式ドキュメントを優先し、詰まったところを第三者情報に頼る」という至ってまっとうな形で進めました。
作る上でのメモ
以下は、今後同様のことをするときのために、わかりにくかった点をメモしておきます。
iamロールの設定が必要ですよ
serverlessを導入するにあたって、公式ドキュメントにあるように、"Configuring AWS"から設定しておきましょう。serverlessのプロジェクトを作る前に設定しておかないと、_meta/variables/s-variables-dev-{region名}.json
のiamRoleArnLambda
に適切なキーがアサインされず、handler.jsの実行時にエラーになりますので要注意です。
aws console iamでこんな感じになっていればOK
iamロールについては、以下が分かりやすかったです。
Serverless Optimizer Pluginを入れないと無理
lambdaにUPするコード(ここではhandler.js)にrequireがある場合は、browserifyしてrequire先のコードも1つのファイルにまとめるプラグインが無いと無理でした。
※ これは前述のqiita記事を読まないとわからなかったです。
API Gatewayからserverlessへのパラメータの受け渡しはどうする?
本来は、s-templates.json
なるものを作って、任意のendpointに適用していく形のようですが、まどろっこしかったので、qiitaのサンプルのやり方を踏襲してs-function.json
内で書けば動いたのでそれでいきました。
{ "name": "facebook", "runtime": "nodejs4.3", "description": "Serverless Lambda function for project: FBBot", "customName": false, "customRole": false, "handler": "handler.handler", "timeout": 6, "memorySize": 1024, "authorizer": {}, "custom": { "excludePatterns": [], "optimize": { "exclude": ["aws-sdk"], "transforms": [ { "name": "babelify", "opts": { "presets": ["es2015"] } } ] } }, "endpoints": [ { "path": "facebook", "method": "GET", "type": "AWS", "authorizationType": "none", "authorizerFunction": false, "apiKeyRequired": false, "requestParameters": { "integration.request.querystring.hub.verify_token": "method.request.querystring.hub.verify_token", "integration.request.querystring.hub.challenge": "method.request.querystring.hub.challenge", "integration.request.querystring.hub.mode": "method.request.querystring.hub.mode" }, "requestTemplates": { "application/json": { "verify_token": "$input.params('hub.verify_token')", "challenge": "$input.params('hub.challenge')", "mode": "$input.params('hub.mode')", "method": "$context.httpMethod" } }, "responses": { "400": { "statusCode": "400" }, "default": { "statusCode": "200", "responseParameters": {}, "responseModels": { "application/json;charset=UTF-8": "Empty" }, "responseTemplates": { "text/plain": "$input.path('$')" } } } }, { "path": "facebook", "method": "POST", "type": "AWS", "authorizationType": "none", "authorizerFunction": false, "apiKeyRequired": false, "requestParameters": {}, "requestTemplates": { "application/json": { "entry": "$input.json('entry')", "method": "$context.httpMethod" } }, "responses": { "400": { "statusCode": "400" }, "default": { "statusCode": "200", "responseParameters": {}, "responseModels": { "application/json;charset=UTF-8": "Empty" }, "responseTemplates": { "text/plain": "$input.path('$')" } } } } ], "events": [], "environment": { "SERVERLESS_PROJECT": "${project}", "SERVERLESS_STAGE": "${stage}", "SERVERLESS_REGION": "${region}" }, "vpc": { "securityGroupIds": [], "subnetIds": [] } }
参考:
http://docs.serverless.com/docs/templates-variablesdocs.serverless.com
handler.jsはこんな感じ
'use strict'; const request = require('request'); const FB_MESSANGER_TOKEN = 'xxxxxx'; module.exports.handler = function(event, context, cb) { switch (event.method.toUpperCase()) { case 'GET': { if (event.mode === 'subscribe' && event.verify_token === FB_MESSANGER_TOKEN) { const validRequest = event.verify_token; return cb(null, validRequest ? event.challenge : 'Error, wrong validation token'); } } case 'POST': { event.entry.forEach(function(pageEntry) { pageEntry.messaging.forEach(function(messagingEvent) { if (messagingEvent.message) { receivedMessage(messagingEvent); } }); }); return cb(null, 'OK'); } default: return cb('Error, Invalid Method'); } }; function receivedMessage(event) { var senderID = event.sender.id; var recipientID = event.recipient.id; var timeOfMessage = event.timestamp; var message = event.message; console.log("Received message for user %d and page %d at %d with message:",senderID, recipientID, timeOfMessage); console.log(JSON.stringify(message)); var messageId = message.mid; // You may get a text or attachment but not both var messageText = message.text; var messageAttachments = message.attachments; if (messageText) { sendTextMessage(senderID, messageText); } else if (messageAttachments) { sendTextMessage(senderID, "Message with attachment received"); } } function sendTextMessage(recipientId, messageText) { var messageData = { recipient: { id: recipientId }, message: { text: messageText } }; callSendAPI(messageData); } function callSendAPI(messageData) { request({ uri: 'https://graph.facebook.com/v2.6/me/messages', qs: { access_token: FB_MESSANGER_TOKEN }, method: 'POST', json: messageData }, function (error, response, body) { if (!error && response.statusCode == 200) { var recipientId = body.recipient_id; var messageId = body.message_id; console.log("Successfully sent generic message with id %s to recipient %s", messageId, recipientId); } else { console.error("Unable to send message."); console.error(response); console.error(error); } }); }
誰でもbotにアクセスできるわけではない
ここまでの手順で、botサービスを一般公開できるわけではありません。一般公開するには、facebookの審査に通る必要があります。
じゃあどうやって審査に出せばいいの?というと恐らく以下のようになるかと思います。ただし実際に試したわけではないのであくまで推測になります。
- facebook developerの当該アプリのダッシュボードにて、左側のサイドバーからmessengerを選択し、スクショの1,2のボタンを押して申請します。
- 左側のサイドバーからアプリレビューを選択し、
page_messaging
の項目でノートを編集
ボタンを押します。
- さらにその先で、プラットフォームポリシーに準拠しているかどうかの確認と、使い方のスクリーンキャストの提出を求められるので、それらを入力します。
- 承認されれば、晴れて一般公開となると思われます。
botを誰かに試して欲しい場合はテスターとして追加する
画像のように、テスターとして役割に追加してあげれば、botを試してもらうことができます。
感想
今回はとりあえず、serverlessを使ってmessengerでテキストを入力するとオウム返しするbotを作りました。感想としては、おもったよりレスポンスが遅いなー(0.5秒くらいな感覚)と思いました。handler.jsの中身の処理がかさむと恐らくもっと重くなると思われます。
wit.aiは音声認識が付いているので使いたいですが、概念を理解するのに人より多く時間を割かないといけなさそうでだるいなーというところです。
ということで、引き続き触っていきます。