ランダムにお店を選んでくれるLine Botを作った。
「?飯」というコマンドの後に改行で地名と予算を入れて呟くと、ぐるなびからランダムに3件選んでURLを返すBOTをつくりました。
課題
基本的にアルコールが飲めないのと、食べ物に対する好き嫌いはあれどこだわりが一切ないので、「どこか店決めといて」と言われた際におすすめできるような店のストックが自分のなかにありません。仕方がないので、食べログやくるナビなどを検索して「この店どう?」といった提案をするわけですが、「私のおすすめの店 = ぐるなびの検索結果」なら、別にBotでいいじゃないかと思いついたので作ってみました。
仕組み
Line botはGoogle Apps Scriptを使って作ってます。
初めはAWS Lamdaを使う予定でしたが、これだけのためにAPI Gateway の設定とかするのもめんどくさいし、GASだと1ファイルで作れて楽そうだったので。
お店の情報は「ぐるなび Web Service」の「レストラン検索API」を使って取得しています。
Line側の設定
LINE Developersに登録し、プロバイダーを作成、新規チャンネルとして「Messaging API」を登録します。
今回はお試しなのでプランは「Developer Trial」にしました。
「Messaging API」の設定画面で「Webhook送信」を有効にし、「Webhook URL」にGASのURLを入力しています。
(GASのURLはスクリプトを公開後に取得して入力します)
アクセストークンを生成してメモって置くのを忘れずに。
ぐるなび側の設定
ぐるなびwebサービスに登録し、「マイページ」から「アプリケーションを追加」してアクセスキーを取得します。
Google App Scriptの設定
Googleドライブで「新規→その他→Google Apps Script」を選択し、新たなスクリプトファイルを作成します。
サンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
// LINE developersのメッセージ送受信設定に記載のアクセストークン var LINE_TOKEN = 'Line message apiのアクセストークン'; var LINE_URL = 'https://api.line.me/v2/bot/message/reply'; //ぐるなび web Service のアクセスキー var GURUNAVI_TOKEN = 'アプリケーションのアクセスキー'; var GURUNAVI_URL = 'https://api.gnavi.co.jp/RestSearchAPI/v3/?'; //postリクエストを受取ったときに発火する関数 function doPost(e) { // 応答用Tokenを取得 var replyToken = JSON.parse(e.postData.contents).events[0].replyToken; // メッセージを取得 var userMessage = JSON.parse(e.postData.contents).events[0].message.text; //メッセージを改行ごと(コマンド、アドレス、予算)に分割 var command = userMessage.split("n"); var tag = command[0]; //コマンド取得 // 呟かれた内容がbot宛てでない場合はなにもしない。 if(!tag == "?飯") return null; var address = command[1]; //住所取得 var budget = command[2]; //予算取得 //ぐるなびに問合せて店情報を取得 var shops = getShopData(address, budget); //返答用メッセージを作成 var messages = [ { 'type': 'text', 'text': "こんなお店はどうですか?", } ] /* //なんかうまくいかない shops.forEach(function(shop){ var meg = { 'type': 'text', 'text': shop.url, } messages.push(meg); }); */ var meg1 = { 'type': 'text', 'text': shops[0].url, } messages.push(meg1); var meg2 = { 'type': 'text', 'text': shops[1].url, } messages.push(meg2); var meg3 = { 'type': 'text', 'text': shops[2].url, } messages.push(meg3); //lineで返答する UrlFetchApp.fetch(LINE_URL, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + LINE_TOKEN, }, 'method': 'post', 'payload': JSON.stringify({ 'replyToken': replyToken, 'messages': messages, }), }); ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON); } //ぐるなび問合せ function getShopData(address, budget){ // リクエストパラメーター var param = { "keyid" : GURUNAVI_TOKEN, "address" : address, "hit_per_page":100 } //パラメータを文字列に変換 var pramStr = Object.keys(param).map(function(key){ return key+"="+param[key]}).join("&") //ぐるなびに送信 var url = GURUNAVI_URL+pramStr; var response = UrlFetchApp.fetch(url); var content = response.getContentText("UTF-8"); var resJson = JSON.parse(content) //予算でフィルタリング var filtered = (budget) ? resJson.rest.filter(function(item){ return item.budget <= budget}) : resJson.rest; //ランダムに店をセレクト var randomize = goodShuffle(filtered); var selectShop = randomize.slice(0, 5); return selectShop.map(function(d){ return {name:d.name, url:d.url} }); } var goodShuffle = function (arr) { var i, j, temp; arr = arr.slice(); i = arr.length; if (i === 0) { return arr; } while (--i) { j = Math.floor(Math.random() * (i + 1)); temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } return arr; }; |
GASを「ウェブアプリケーション」として公開するとURLが取得できるます。
取得したURLをLine message APIの設定画面でWebhook URLとして登録すれば完成です。
総括
エラー処理もまったくしていない、なぜかforEachメソッドを使うと返答されないというバグの原因も不明なままのざっくりとしたスクリプトですが、とりあえずBotとしては機能しています。
思った以上に簡単に作れて楽しいのでおすすめです。
今後の展開としては、ぐるなびから取得した情報のうちURLしか返さない手抜き仕様を、もうちょっと頑張ってちゃんとテンプレートメッセージ(JSON)を生成してみやすい返答にするのと、フィルタリング条件を予算以外でもできるようにしたいかと思います。