ギニュー特戦隊に入りたい
皆さんも(特に男性なら)、人生で一度はギニュー特戦隊に入隊したいと思いましたよね?
今回はその願いを少しでも叶えるべく、次のようなボットを作成しました。
* まさかそんな人はいないと思いますが、ギニュー特戦隊を知らない方はこちらのwikipediaをご確認ください。
ギニュー特戦隊識別bot完成!
— 北城雅照@足立慶友整形外科 (@kutuyanomusuko) November 27, 2020
僕はリクームでしたwww#protooutpic.twitter.com/52wTNdbfTu
早速使ってみたい方は、一番下にQRコードを貼っておきますので、ご利用ください。
ちなみに、万が一、リクームとジース以外の方に似ていると判定されたら、その方は人間(ホモ・サピエンス)という概念を超えている方ですので、すぐにご連絡ください!
開発環境の下準備
1) VScodeのインストール
VScodeのインストールついては、googleなどで他の記事を検索してください。
2) node.jsとnpmのインストール
Macでの環境作りは、こちらの別の記事にまとめてあります。
参考にしてください。
Macにnode.js,npmのインストール方法
開発環境の準備
1) ginyuforceというフォルダを作成
2) VSCodeで上記フォルダを開き、フォルダ内にginyuforce.jsを作成
3) VSCode内でターミナルを開き、フォルダをnpm管理できるように初期化
$ npm init -y
システムの概要
Teachable Machineによる画像認識AIの作成
以前の記事(誰が使うかわからないけど、膝のレントゲン写真を送ったら、その膝がどの程度痛んでいるのか教えてくれるラインbotを作ってみた。)では画像判定AIをAIメーカーで作成したので、今回はTeachable Machineを使用し、画像判定AIを作成しました。
* 使い方については、こちらの記事>【備忘録】Teachable Machineの利用方法が参考になりました。ぜひ一度お読みください。(よかったらLGTMをお願いします。)
ginyuforce.jsのコード
'use strict';// おまじないconst{JSDOM}=require('jsdom');vardom=newJSDOM('');global.document=dom.window.document;global.HTMLVideoElement=dom.window.HTMLVideoElement;constcanvas=require('canvas');global.fetch=require('node-fetch');consttmImage=require('@teachablemachine/image');constexpress=require('express');constline=require('@line/bot-sdk');constfs=require('fs');constPORT=process.env.PORT||3000;constconfig={channelSecret:'自身が作成したLINEbotのシークレットトークンを入力',channelAccessToken:'自身が作成したLINEbotのアクセストークンを入力',};// Teachable Machineletmodel;// https://teachablemachine.withgoogle.com/// ここでエクスポート、クラウドにモデルをアップロードした後に取得できるconstURL='作成したモデルのTeachable Machineのリンクを入力';// ########################################// Teachable Machineを使って画像分類をする部分// ########################################// 初期化が時間かかるので、node立ち上げ時に行うようにするasyncfunctioninitTeachableMachine(){constmodelURL=URL+'model.json';constmetadataURL=URL+'metadata.json';// モデルデータのロードmodel=awaittmImage.load(modelURL,metadataURL);// クラスのリストを取得// const classes = model.getClassLabels();// console.log(classes);}initTeachableMachine();asyncfunctionpredict(imgPath){// canvasに画像をロードするconstimage=awaitcanvas.loadImage(imgPath);// 判定するconstpredictions=awaitmodel.predict(image);// 一番近いもの順でソートpredictions.sort((a,b)=>{returnb.probability-a.probability;});returnpredictions;}// ########################################// LINEサーバーからのWebhookデータを処理する部分// ########################################// LINE SDKを初期化しますconstclient=newline.Client(config);// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されますasyncfunctionhandleEvent(event){// 受信したWebhookが「画像以外」であればnullを返すことで無視しますif(event.message.type==='image'){console.log("画像が送られてきた");// 画像を保存constdownloadPath='./01.png';//左記の名前で使用中のフォルダ内に送信された画像が保存されるconstgetContent=awaitdownloadContent(event.message.id,downloadPath);constresult=awaitpredict(getContent);// AIメーカーAPIの結果から、返信するメッセージを組み立てるlettext='';letname='';name=result[0].className// 判定結果をテキストに代入text='あなたは『'+name+"』に最も似ています!";// これまでの結果を確認するためにコンソールに表示console.log(result);console.log(name);console.log(text);// 判定結果に応じた画像を送信if(name==='ジース'){returnclient.replyMessage(event.replyToken,[{type:'text',text:text},{type:'image',originalContentUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/gisu.jpg',previewImageUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/gisu.jpg'}]);}elseif(name==='リクーム'){returnclient.replyMessage(event.replyToken,[{type:'text',text:text},{type:'image',originalContentUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/rikumu.jpg',previewImageUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/rikumu.jpg'}]);}elseif(name==='グルド'){returnclient.replyMessage(event.replyToken,[{type:'text',text:text},{type:'image',originalContentUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/gurudo.jpg',previewImageUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/gurudo.jpg'}]);}elseif(name==='バータ'){returnclient.replyMessage(event.replyToken,[{type:'text',text:text},{type:'image',originalContentUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/bata.jpg',previewImageUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/bata.jpg'}]);}elseif(name==='ギニュー隊長'){returnclient.replyMessage(event.replyToken,[{type:'text',text:text},{type:'image',originalContentUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/ginyu.jpg',previewImageUrl:'https://sleepy-mirzakhani-f338f8.netlify.app/ginyu.jpg'}]);}}// 「テキストメッセージ」であれば、受信したテキストをそのまま返事しますif(event.message.type==='text'){returnclient.replyMessage(event.replyToken,{type:'text',text:event.message.text// ← ここに入れた言葉が実際に返信されます});}}// ########################################// LINEで送られた画像を保存する部分// ########################################functiondownloadContent(messageId,downloadPath){constdata=[];returnclient.getMessageContent(messageId).then((stream)=>newPromise((resolve,reject)=>{constwritable=fs.createWriteStream(downloadPath);stream.on('data',(chunk)=>data.push(Buffer.from(chunk)));stream.pipe(writable);stream.on('end',()=>resolve(Buffer.concat(data)));stream.on('error',reject);}));}// ########################################// Expressによるサーバー部分// ########################################// expressを初期化しますconstapp=express();// HTTP GETによって '/' のパスにアクセスがあったときに 'Hello LINE BOT! (HTTP GET)' と返事します// これはMessaging APIとは関係のない確認用のものですapp.get('/',(req,res)=>res.send('<h1>Hello LINE BOT! (HTTP GET)</h1>'));// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をしますapp.post('/webhook',line.middleware(config),(req,res)=>{// Webhookの中身を確認用にターミナルに表示しますconsole.log(req.body.events);// 空っぽの場合、検証ボタンをクリックしたときに飛んできた"接続確認"用// 削除しても問題ありませんif(req.body.events.length==0){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サーバーを実行中です…`);
実行に必要なパッケージのインストルール
下記のコードを入力し、実行に必要なパッケージを入力する。
2) Teachable Machineを動かすのに必要なパッケージ
$ npm i @line/bot-sdk express
1) LINEbotを動かすのに必要なパッケージ
$ npm i @teachablemachine/image @tensorflow/tfjs canvas jsdom
Herokuへのデプロイ
node.jsが動作する無料のクラウドサーバーであるHerokuにデプロイします。
下準備
1) Heroku CLIのインストール
https://devcenter.heroku.com/articles/heroku-cli
2) Herokuアカウントの作成
https://signup.heroku.com/
デプロイ
ターミナルで下記コマンドを実行します。
$ heroku login
実行するとブラウザが自動的に起動するので、ログインします。
すると、ターミナル上でもログインが完了します。
その後、package.jsonの"scripts"の中に、"start"を下記のように追記し保存します。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node ginyuforce.js"
},
Heroku内にデプロイ先のディレクトリを作成します。
下記の順でターミナルにコマンドを入力します。
$ git init
$ heroku create 名付けたいデプロイ先の名前 //付けたい名前がなければ入力なしでもOK
Heroku内にデプロイ先のディレクトリが作成されると、ターミナルに下記のように表示されます。
Creating app... done, ⬢ デプロイ先の名前
https://デプロイ先の名前.com/ | https://git.heroku.com/デプロイ先の名前.git
このデプロイ先ディレクトリに、作成したディレクトリを入れていきます。
下記の順でターミナルにコマンドを入力します。
$ git add .
$ git commit -m 'init'
$ git push heroku master
最終的に下記のように表示されれば完了です。
remote: https://デプロイ先の名前.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/デプロイ先の名前.git
* [new branch] master -> master
これでデプロイ完了です。
ファイルを更新する時
まず、更新するファイルが入ったディレクトリがherokuのデプロイ先のディレクトリと紐づいているかを確認します。
$ git remote -v
紐づいている場合
紐づいている場合は、ターミナルに下記のように表記されます。
heroku https://git.heroku.com/heroku上のデプロイ先の名前 (fetch)
heroku https://git.heroku.com/heroku上のデプロイ先の名前 (push)
紐づいていない場合
紐づいていない場合は、ターミナルに下記のように表記されます。
fatal: not a git repository (or any of the parent directories): .git
その場合は、ターミナルに下記の順に入力し、空のディレクトリを作成し、heroku上のデプロイしたいディレクトリと紐付けを行います。
$ git init //空のディレクトリを作成
$ heroku git:remote -a heroku上のデプロイしたいディレクトリ名
//herokuのデプロイ先と先ほど作成した空のtディレクトリを紐付け
その上で、下記の順にコマンドを入力し、ファイルを更新します。
$ git add .
$ git commit -m 'upd'
$ git push heroku master
LINE Developersからbot作成
1) LINE Developersにアクセスし、LINEアカウントでログイン
2) プロバイダー作成
3) 新規チャンネルの作成
4) チャネルアクセストークンとチャネルシークレットの取得
1)〜4)までは下記を参考に進みました。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest
5) webhookの設定
Herokuから取得したデプロイ先のURLを入力。
/webhookをつけることを忘れずに。
QRコード
完成したギニュー特戦隊判定LINEbotのQRコードがこちらです。
どうでしたか皆さん?
ギニュー特戦隊に成る願いは叶えらましたか??
その他の記事
近すぎると小池都知事が『密です。』と連呼するデバイスを作ったら腹筋が崩壊したので、皆さんにも試して欲しい。
誰が使うかわからないけど、膝のレントゲン写真を送ったら、その膝がどの程度痛んでいるのか教えてくれるラインbotを作ってみた。