目的
LINEBotを使って、対話でうまくブルワリーの情報を探したい!
なぜLINEか?
⇒老若男女問わず使えるインターフェースですから!
なぜブルワリーか?
⇒お酒が、、好きなんです。
前提
記事を読まれる前に、、、
まだまだやりたいことの最初の慣れの部分なので、
えっ?なんで?と思うことは多いかと思います。
今回やったこと
ブルワリー検索APIの「Open Brewery DB」と「LINE MessagingAPI」を使って、
LINEのトーク画面からニューヨークのブルワリーを検索して、一覧をLINEのレスポンスとして返す。
URL付きでページにとんだり、電話をかけやすくするなど。
やってみてわかったこと
★流れが何となく見えた。
ユーザがLINEから何かメッセージをうつ。
→LINEサーバにまず送られる。
→LINEのサーバからWebhookでイベントがとんでくる。
→イベントの何を取るのか、チェックしつつ、来た内容に対してどう返すかをプログラムで作る。
リクエストのイベントが来るところの受け方は、
詳しくはLINEのドキュメントをもっと見たほうが良いと思った。
https://developers.line.biz/ja/reference/messaging-api/
ソース
'use strict';// おまじない// ########################################// 初期設定など// ########################################// パッケージを使用しますconstexpress=require('express');constline=require('@line/bot-sdk');constaxios=require('axios');constfs=require('fs');// ローカル(自分のPC)でサーバーを公開するときのポート番号ですconstPORT=process.env.PORT||3000;// Messaging APIで利用するクレデンシャル(秘匿情報)です。constcredential=JSON.parse(fs.readFileSync('./credential/credential.json','utf8'));constconfig={channelSecret:credential.channelSecret,channelAccessToken:credential.channelAccessToken};// ユーザのメッセージに対してどう返すかを定義constsampleFunction=async(event)=>{// ユーザーメッセージが想定しているものかどうかif(check_params(event.message.text)){returnclient.replyMessage(event.replyToken,{type:'text',text:'ニューヨークのブルワリーは?と話しかけてね'});}else{// 「リプライ」を使って先に返事しておきますawaitclient.replyMessage(event.replyToken,{type:'text',text:'調べています……'});letpushText='';try{// axiosでニューヨークブルワリーリストのAPIを叩きます(少し時間がかかる・ブロッキングする)constres=awaitaxios.get('https://api.openbrewerydb.org/breweries?by_state=new_york');console.log(res.data);constbrewery_data=res.data;for(letj=0;j<brewery_data.length;j++){constb_name=brewery_data[j].name;constb_url=brewery_data[j].website_url;console.log(b_name);if(j===0){pushText='ここ!\r\n';}else{pushText=pushText+'店名 '+b_name+'\r\n'+'URL '+b_url+'\r\n\r\n';}}}catch(error){pushText='検索中にエラーが発生しました。ごめんね。';// APIからエラーが返ってきたらターミナルに表示するconsole.error(error);}// 「プッシュ」で後からユーザーに通知しますreturnclient.pushMessage(event.source.userId,{type:'text',text:pushText,});}};functioncheck_params(event_text){if(event_text==='ニューヨークのブルワリーは?'){returnfalse;}else{returntrue;}}// ########################################// LINEサーバーからのWebhookデータを処理する部分// ########################################// LINE SDKを初期化しますconstclient=newline.Client(config);// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されますasyncfunctionhandleEvent(event){// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視しますif(event.type!=='message'||event.message.type!=='text'){returnPromise.resolve(null);}// サンプル関数を実行しますreturnsampleFunction(event);}// ########################################// Expressによるサーバー部分// ########################################// expressを初期化しますconstapp=express();// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をしますapp.post('/webhook',line.middleware(config),(req,res)=>{// Webhookの中身を確認用にターミナルに表示しますconsole.log(req.body.events);// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT! (HTTP POST)');// LINEサーバーに返答しますconsole.log('検証イベントを受信しました!');// ターミナルに表示しますreturn;// これより下は実行されません}// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返しますPromise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result));});// 最初に決めたポート番号でサーバーをPC内だけに公開します// (環境によってはローカルネットワーク内にも公開されます)app.listen(PORT);console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
環境
Node.js v14.9.0
Visual Studio Code v1.49.3
@line/bot-sdk
結果
【おまけ】本当は、やれたらやりたいこと
■技術
・ユーザから送られたメッセージのチェック(関数切り出し)
・LINEに表示された際に、URLから取得されたサイトのサムネイル?がMAX5件ぐらいなので、
取得も5件ぐらいの方が見やすそう。
・認証情報は、見えそうなファイルよりも、もっと隠れたところから取得したほうが良いと思う。
・リッチメニューを使ってそもそもどんな操作をすればよいのかユーザにわかりやすくする。
(フリーテキストって何入れればええのかわからない。)
・Googleマップのリンクを付けて保存しやすくする。
■企画
・ビールも好きだけど、肉やカレーも。。。