Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8835

家庭内フードロスを減らそう。LINEbotを使ったレシピの提案

$
0
0

夏が近づき暖かくなってきました。
食品も傷みやすい季節になってきましたね!
また、在宅ワークも進み家でのお昼ご飯などのレシピにも困っているのではないでしょうか?

ということで、今回は家庭内でのフードロスが減るよう、余っている食材をメッセージするとレシピのリンクを返してくれるボットを作って見ました。

1 材料に関連したレシピがある場合:

2 材料に関連したレシピがない場合(ランダムで料理のカテゴリを提案します):

※ カルーセルやボタンテンプレートのサムネはprotoout studioさんの可愛いアイコンをかりました。

では説明していきます。

前提

基本的なLINEbotの作り方はここではあまり詳しく書かないので、初めての方は下記ページを参考にしてみてください。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest

楽天レシピ系API

今回、レシピに関する情報は楽天レシピカテゴリーAPI楽天レシピカテゴリ別ランキングAPIを利用しました。
これらのAPIはドキュメントにあるように、基本的に料理のカテゴリーや、特定のカテゴリーでの上位4位までにランクインされているレシピを返してくれます。

準備

楽天レシピ系のAPIを利用するにはアプリIDの発行が必要なので、まず発行します。
image.png

発行が完了すると、APIを使うときに必要なアプリID/デベロッパーIDなどの情報が表示されるのでそれはメモしておきます。

ソースコード

早速ですが、ソースコードです。

recipe.js
'use strict';constexpress=require('express');constline=require('@line/bot-sdk');constPORT=process.env.PORT||3000;// 追加constaxios=require('axios');constconfig={channelSecret:'xxxxxx',channelAccessToken:'xxxxxx'};constapp=express();app.get('/',(req,res)=>res.send('Hello LINE BOT!(GET)'));//ブラウザ確認用(無くても問題ない)app.post('/webhook',line.middleware(config),(req,res)=>{// LINE上で入力されたconsole.log(req.body.events[0].message.text);//ここのif文はdeveloper consoleの"接続確認"用なので後で削除して問題ないです。if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT!(POST)');console.log('疎通確認用');return;}Promise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result));});constclient=newline.Client(config);//////////////// ここ以降が処理を書く場所 ///////////////asyncfunctionhandleEvent(event){if(event.type!=='message'||event.message.type!=='text'){returnPromise.resolve(null);}letmes=''varresult=event.message.text;mes=result+'を使ったレシピ';//wikiのurlの前の一言awaitclient.replyMessage(event.replyToken,{type:'text',// text: event.message.text //実際に返信の言葉を入れる箇所text:mes});returngetMenu(event.source.userId,result);}//handleevent constgetMenu=async(userId,food)=>{constres=awaitaxios.get('https://app.rakuten.co.jp/services/api/Recipe/CategoryList/20170426?format=json&formatVersion=2&categoryType=small&applicationId='+{楽天のアプリID/デベロッパーID});varname=[];varcatgid=[];varurl=[];varlen=res.data.result.small.length;vara=0;for(vari=0;i<len;i++){if(res.data.result.small[i].categoryName.indexOf(food)>-1){name[a]=res.data.result.small[i].categoryName;catgid[a]=res.data.result.small[i].parentCategoryId;url[a]=res.data.result.small[i].categoryUrl;a=a+1;}}console.log(name);console.log(catgid);console.log(url);letcol=[];// 何も引っかからなかった時の処理if(name.length<=0){// とりあえず返事するawaitclient.pushMessage(userId,{type:'text',text:'ごめん、その食材の使い方は知らない。代わりのおすすめメニュー↓↓',});// ランダムでこの中の物を返すためのリストletcategory=[{categoryName:"人気メニュー",categoryId:"30",categoryUrl:"https://recipe.rakuten.co.jp/category/30/"},{categoryName:"定番の肉料理",categoryId:"31",categoryUrl:"https://recipe.rakuten.co.jp/category/31/"},{categoryName:"定番の魚料理",categoryId:"32",categoryUrl:"https://recipe.rakuten.co.jp/category/32/"},{categoryName:"卵料理",categoryId:"33",categoryUrl:"https://recipe.rakuten.co.jp/category/33/"},{categoryName:"パスタ",categoryId:"15",categoryUrl:"https://recipe.rakuten.co.jp/category/15/"},{categoryName:"鍋料理",categoryId:"23",categoryUrl:"https://recipe.rakuten.co.jp/category/23/"},{categoryName:"簡単料理・時短",categoryId:"36",categoryUrl:"https://recipe.rakuten.co.jp/category/36/"},{categoryName:"節約料理",categoryId:"37",categoryUrl:"https://recipe.rakuten.co.jp/category/37/"},{categoryName:"今日の献立",categoryId:"38",categoryUrl:"https://recipe.rakuten.co.jp/category/38/"},{categoryName:"健康料理",categoryId:"39",categoryUrl:"https://recipe.rakuten.co.jp/category/39/"},]varlen=category.length;varrand=Math.floor(Math.random()*(len+1));// 毎度ランダムに変わるようにするvarcategoryName=category[rand].categoryName+'のレシピだよ!';varurl=category[rand].categoryUrl;// ボタンテンプレートreturnclient.pushMessage(userId,{"type":"template","altText":"This is a buttons template","template":{"type":"buttons","thumbnailImageUrl":"{サムネにしたい画像のURL}","imageAspectRatio":"rectangle","imageSize":"cover","imageBackgroundColor":"#FFFFFF","title":"おすすめMenu","text":categoryName,"defaultAction":{"type":"uri","label":"View detail","uri":url},"actions":[{"type":"uri","label":"レシピへGO","uri":url}]}});}else{varlen2=name.length;if(len2>10){len2=10;}// カルーセルの上限が10個なので10以上ある場合は10にする// "columns" の中身を作っておく  for(vark=0;k<len2;k++){consttitle=name[k];consttext=name[k]+'のレシピを紹介するよ!';consturi=url[k];letcarousel={"thumbnailImageUrl":"{サムネにしたい画像のURL}","imageBackgroundColor":"#FFFFFF","title":title,"text":text,"defaultAction":{"type":"uri","label":"View detail","uri":uri},"actions":[{"type":"uri","label":"レシピへGO","uri":uri}]};col.push(carousel);}returnclient.pushMessage(userId,{"type":"template","altText":"this is a carousel template","template":{"type":"carousel","columns":col,"imageAspectRatio":"rectangle","imageSize":"cover"}});}}(process.env.NOW_REGION)?module.exports=app:app.listen(PORT);console.log(`Server running at ${PORT}`);

説明

本当は材料をメッセージしたらその材料を使った料理を返すようにしたかったのですが、それは楽天レシピAPIをそのまま使うだけではできなかったので、まず使ったAPIは/Recipe/CategoryListのほうをcategoryType=smallで取ることで、入力した値をヒットしやすくなります。

入力値がAPIで返ってきた値とヒットした場合は、それを配列に入れてカルーセルで出すための準備をします。
もし、「ゴメス」のようなヒットしない値だった場合は、categoryType=largeの分類のボタンテンプレートでランダムに出すようにしています。

LINEのカルーセルやボタンテンプレートなどに関しては下記が参考になります。
■楽天のAPIを使ってマスクを買えるBotを作ってみた[LINEBotリッチメニュー]
■LINEの公式ドキュメント

作ってみて

厳密に食材に対してのレシピを返してくれるわけじゃないけど、まあまあ使えると思います。
ぜひお試しください!


Viewing all articles
Browse latest Browse all 8835

Trending Articles