通常のチャットボットは1問1答式ですが、データベースと連携することで1問1答式以外の可能性が広がると思い、試しにこんなものを作りました。
私が若かりし頃(30年前くらい)のコンパとかの宴会芸のネタの1つですww
作ったもの
LINEチャットボット
「心を読む猫ボット」
ちなみに、iPhoneXへのはめ込み画像はこちらで作りました。
https://mockuphone.com/
何をするチャットボットなの?
数回の質問で、頭の中にある数字をあてます。
つまりあなたの心を読むということです。
なぜ、猫なのかというと、テキストだけでは寂しいですし、老若男女に大人気の猫に便乗して少しでも利用してもらおうという姑息な手マーケティング手法です。
それに、今思い付いたのですが、心を読むチャットボットに飽きても、猫画像に癒やされるチャットボットとして長く利用してもらえるという狙いもあるのです。
ちなみにリッチメニュー「タッチしてください」の画像は、我が家の猫ちゃんです。
動画
チャットボットが人の心を読むなんて信じないでしょうから、その証拠動画をお見せいたしましょう。
ちなみにこの動画は、@tkyko13さんに教えてもらったGyazoというサービスを利用しました。
これで、興味津々になった方は、今すぐこちらのQRコードにスマホのカメラを向けましょう。
システム
環境
- Node 14.5.0
構成図
ボットが数回質問した内容からユーザーの頭の中にある数字を当てるという仕組みです。
過去のデータの蓄積が必要なのでデータベースとしてGoogleスプレッドシートを利用しました。
プログラムは node.jsで、herokuに構築しました。
node.jsをherokuに構築するには、実行プログラムと同じディレクトリに Procfile を追加するだけで、できました。
web: node app.js
使用API
- LINE Messaging API
Node.jsでLINE BOTを作る方法はこちらを参考にしました
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 - Google Sheets API
過去の情報を保有するためにGoogleスプレッドシートを使いました。- Googleスプレッドシートの導入部分はこちらを参考
Node.js googleapis npmパッケージで Google スプレッドシートを await/async で読み取るメモ 〜1ft-seabass.jp.MEMO - データの読み書きはこちらのサイトを参考
【Node.js + Sheets API v4】Googleスプレッドシートを読み書きする
- Googleスプレッドシートの導入部分はこちらを参考
- TheCatAPI
いろんな猫APIがあります。その中からURLをたたくだけでランダムにネコの画像を取得できるAPIを使用しました。
なぜ心を読めるのか?
超能力です。
というのは冗談で、簡単な算数問題です。
答えはコードの中にもあります。
(コード読むより、普通に考えたほうが簡単ですが・・・)
コード
'use strict';constexpress=require('express');constapp=express();constPORT=process.env.PORT||3000;constaxios=require("axios");constline=require('@line/bot-sdk');//LINE Messaging API のいろいろconstconfig={channelSecret:'LINE_CHANNEL_SECRET',channelAccessToken:'LINE_CHANNEL_ACCESS_TOKEN'};//Googleスプレッドシートを使う設定let{google}=require('googleapis');constcreds={"type":"service_account","project_id":"PROJECT_ID","private_key_id":"PRIVATE_KEY_ID","private_key":"PRIVATE_KEY","client_email":"CLIENT_EMAIL","client_id":"CLIENT_ID","auth_uri":"AUTH_URI","token_uri":"TOKEN_URI","auth_provider_x509_cert_url":"AUTH_PROVIDER_X509_CERT_URL","client_x509_cert_url":"CLIENT_X509_CERT_URL"};// JSON Web Token(JWT)の設定letjwtClient=newgoogle.auth.JWT(creds.client_email,null,creds.private_key,['https://www.googleapis.com/auth/spreadsheets','https://www.googleapis.com/auth/drive']);constsheet='SHEET名';// スプレッドシートAPIはv4を使うletsheets=google.sheets('v4');app.post('/webhook',line.middleware(config),(req,res)=>{console.log(req.body.events);//ここの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){//GoogleスプレッドシートのJSON Web Token(JWT) の認証letresultJwtClient;try{resultJwtClient=awaitjwtClient.authorize();}catch(error){console.log("Auth Error: "+error);}//シートを読み込むletresponseGetSheet;try{responseGetSheet=awaitsheets.spreadsheets.values.get({auth:jwtClient,spreadsheetId:sheet,range:"シート1",});}catch(error){console.log('The API returned an error: '+error);}//シートから読み込んだデータletdata=responseGetSheet.data.valuesletbot_message;//返すセリフletnewComerFlag=1;letuserIndexNumber;//アクセス者のインデックス //アクセス者のインデックスを調べる(初めてかどうかも調べる)for(leti=0;i<data.length;i++){if(data[i][0]==event.source.userId){newComerFlag=0;userIndexNumber=i;}}//最初ののアクセスのときの処理if(newComerFlag==1){// googleスプレッドシートへの書き込み(ユーザーID、回数、数字の初期値)bot_message="数字を1つ思い浮かべてください";appendData("シート1!A1",event.source.userId,0,0)}//最後の1つ前のアクセスのときの処理elseif(data[userIndexNumber][1]==4){bot_message="それに、最初に思った数字を引いてください";data[userIndexNumber][1]=Number(data[userIndexNumber][1])+1;//googleスプレッドシートのデータをアップデートupdateData("シート1!"+String(userIndexNumber+1)+":"+String(userIndexNumber+1),data[userIndexNumber][0],data[userIndexNumber][1],data[userIndexNumber][2])}//最後のアクセスの処理elseif(data[userIndexNumber][1]==5){bot_message="今あなたの頭にある数字は "+data[userIndexNumber][2]+"ですね";//googleスプレッドシートの内容を消去するupdateData("シート1!"+String(userIndexNumber+1)+":"+String(userIndexNumber+1),"","","")}else{//通常時のアクセスの処理letplusMinus;letadd_mes;letrandom1=Math.floor(Math.random()*10)+1;if(random1>2){add_mes="を足してください";plusMinus=1;}else{add_mes="を引いてください";plusMinus=-1;}letrandom2=Math.floor(Math.random()*10)+1;bot_message="それに "+random2+add_mes;data[userIndexNumber][2]=Number(data[userIndexNumber][2])+(random2*plusMinus);data[userIndexNumber][1]=Number(data[userIndexNumber][1])+1;//googleスプレッドシート更新(回数、現在の数値)updateData("シート1!"+String(userIndexNumber+1)+":"+String(userIndexNumber+1),data[userIndexNumber][0],data[userIndexNumber][1],data[userIndexNumber][2])}//猫の写真をAPIからランダムにとってくるletcat_picture=awaitaxios.get("https://api.thecatapi.com/v1/images/search");letcat_url=cat_picture.data[0].url;//ボットのメッセージを返す処理returnclient.replyMessage(event.replyToken,{"type":"template","altText":"This is a buttons template","template":{"type":"buttons","thumbnailImageUrl":cat_url,"imageAspectRatio":"rectangle","imageSize":"cover","imageBackgroundColor":"#FFFFFF","title":bot_message,"text":"","defaultAction":{"type":"uri","label":"View detail","uri":cat_url},"actions":[{"type":"message","label":"OK","text":"OK"}]}});}//googleスプレッドシートにデータを追加(行を追加)asyncfunctionappendData(range0,value1,value2,value3){letresponseAppendSheet;try{responseAppendSheet=awaitsheets.spreadsheets.values.append({auth:jwtClient,spreadsheetId:sheet,range:range0,valueInputOption:"USER_ENTERED",insertDataOption:"INSERT_ROWS",resource:{values:[[value1,value2,value3]]}});}catch(error){console.log('The API returned an error: '+error);}}//googleスプレッドシートのデータをアップデート(上書き)asyncfunctionupdateData(range0,value1,value2,value3){letresponseAppendSheet;try{responseAppendSheet=awaitsheets.spreadsheets.values.update({auth:jwtClient,spreadsheetId:sheet,range:range0,valueInputOption:"USER_ENTERED",resource:{values:[[value1,value2,value3]]}});}catch(error){console.log('The API returned an error: '+error);}}app.listen(PORT);console.log(`Server running at ${PORT}`);
フローチャート
ちなみに、このフローチャートはこちらで作りました。
draw.io
https://www.draw.io/
可能性
LINEのチャットボットを外部のデータベースとやりとりできれば、可能性が広がります。
ぱっと浮かんだだけで、以下のようなことができそうなので、気が向いたらチャレンジしてみようと思います。
- しりとり、山手線ゲーム
- ポーカーなどのトランプ
- アドベンチャーゲーム、脱出ゲーム
- LINEから外部の機械やガジェットを操作
- センサーからマイコンを通じて情報取得
- 会話のやりとりをクラウドに保存して機械学習
- Unityと連携したゲームや、メディアアート