『極上のミートソースパスタ』をゲーム感覚で作ろう

## 美味しいパスタを作ろう
今回は、イタリアン料理を作るのが趣味な自分が、イタリアン料理の王道『ミートソースパスタ』を美味しく作るためのアプリっぽいものを作ってみようと思う。

## 完成作品
動画をまじめに作ったので、ぜひ「いいね」待ってます。

https://twitter.com/ySuljbjE7vLmUov/status/1528525242423181313

## 環境等
<dt>環境</dt>
<dd>Heroku環境上でNode-REDを使用</dd>
<dt>使用ツール</dt>
<dd>LINEmessagingAPI</dd>
<dd>Teachable Machine</dd>

## やろうと思ったこと
* パーソナルコーチが、料理の出来栄えをチェックしてくれる。
* 楽しく作りたい。

これらの要素を満たすため、
* 出来栄えチェック⇒TeachableMachine（機械学習）でチェック
* 楽しく作りたい⇒指摘はゲーム風

ということにした。

ゲーム風のコメントをフレーバーテキストというらしい。
遊戯王カードのモンスターの説明に書いてあるようなやつ。

## 完成フロー
フローの全体観。
画像を受け取って、受け取った情報をTeachableMachineで作成したモデルで判定。
判定結果をコメントで返してくれる。
![スクリーンショット 2022-05-22 233522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607557/48a5fd7d-5f97-72b0-c536-ec2cde7be2fa.png)


JSONはこちら。
~~~
[{"id":"3a7b76a0.51c01a","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"4a360a41.040384","type":"ReplyMessage","z":"3a7b76a0.51c01a","name":"","replyMessage":"","x":740,"y":340,"wires":[]},{"id":"77527e17.c1221","type":"function","z":"3a7b76a0.51c01a","name":"フレーバーテキスト","func":"const className = msg.payload[0].class;\nconst scoreName = msg.payload[0].score*100;\nconst scoreName2 = scoreName.toPrecision(4);\nmsg.payload = {};\nmsg.payload.events = [\n    {\n        \"type\": \"message\",\n        \"replyToken\": msg.replyToken,\n        \"message\": {\n            \"type\": \"text\",\n            \"text\": `『${className}』`\n        }\n    }\n];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":280,"wires":[["4a360a41.040384"]]},{"id":"b30786ea.b033d8","type":"http in","z":"3a7b76a0.51c01a","name":"","url":"/webhook","method":"post","upload":false,"swaggerDoc":"","x":290,"y":160,"wires":[["3f906896.69f078"]]},{"id":"3f906896.69f078","type":"function","z":"3a7b76a0.51c01a","name":"","func":"const messageID = msg.payload.events[0].message.id;\nconst replyToken = msg.payload.events[0].replyToken;\n\nmsg.messageID = messageID;\nmsg.replyToken = replyToken;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":160,"wires":[["d1f58790.4267e8"]]},{"id":"d1f58790.4267e8","type":"http request","z":"3a7b76a0.51c01a","name":"","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://api-data.line.me/v2/bot/message/{{{messageID}}}/content","tls":"","persist":false,"proxy":"","authType":"bearer","x":650,"y":160,"wires":[["eba087ae.fbbe88"]]},{"id":"eba087ae.fbbe88","type":"teachable machine","z":"3a7b76a0.51c01a","name":"teachable machine","mode":"online","modelUrl":"https://teachablemachine.withgoogle.com/models/pI-FNA6Y1/","localModel":"teachable_model","output":"best","activeThreshold":false,"threshold":80,"activeMaxResults":false,"maxResults":3,"passThrough":true,"x":490,"y":220,"wires":[["77527e17.c1221"]]}]
~~~


## 参考サイト
殆どこちらの記事を参考にさせて頂いた。とても分かりやすい。

https://atlabo-handson-08.netlify.app/#0


## 1.Teachable Machine
### 1-1.使い方
使い方は多くの記事がネットに転がっている。
例えば、こちらを参考にした。

https://mekurun.com/tips/teachablemachine/

### 1-2.機械学習素材を集める。
自分で刻んだ材料や、パスタを写真で撮りまくって学習させた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607557/b9c8d147-d70d-9dca-2400-fcd5e2ab547f.png)

ちなみに、コーチからのコメントは、Node-red上のJavaScriptで書いてもいいんだが、今回は省エネにするということでクラス名＝コメントにした。
これで、Node-redで判定結果を受け取って表示するだけで良くなる。（後述）


## 2.node-red
ここからは簡単に各ノード内のことを書き残しておく。

### 2-1.http in ノード
画像を受け取るところ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607557/81f334d7-e5e2-8823-ea2b-00cbc27edea3.png)

### 2-2.function ノード
画像の情報を受け取る。
~~~JavaScript
const messageID = msg.payload.events[0].message.id;
const replyToken = msg.payload.events[0].replyToken;

msg.messageID = messageID;
msg.replyToken = replyToken;

return msg;
~~~

### 2-3.http requestノード
画像の情報を受け取る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607557/b58e56e6-6801-2b49-6eb2-f44fd12ef38f.png)

### 2-3.Teachable Machine ノード
事前に学習させた内容で判定をさせる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607557/e8cedde1-3f08-4861-7865-15c374625c6a.png)

### 2-4.function ノード(名前 :フレーバーテキスト) 
返却された結果を表示させるだけ。
ここで、1-2のクラス名をコメントにしたことが活きている。
返却された判定結果に応じてコメントを編集してもかっこいいのだが、今回は表示させるだけで済むようにしている。

~~~JavaScript
const className = msg.payload[0].class;
const scoreName = msg.payload[0].score*100;
const scoreName2 = scoreName.toPrecision(4);
msg.payload = {};
msg.payload.events = [
    {
        "type": "message",
        "replyToken": msg.replyToken,
        "message": {
            "type": "text",
            "text": `『${className}』`
        }
    }
];
return msg;
~~~


## 宣伝
protopediaにも載せています。

https://protopedia.net/prototype/3023

## 作ってみて
機械学習は、2年前くらいに必死に組み込んで作った記憶があるんだが、
こういったツールを使用すれば、今って意外に簡単に出来るんだな。優秀だな。と思った。

あとはミートソースパスタの画像はプロの写真で学習させて、出来栄えも細分化することで、最後の完成形がどんどんプロっぽくなるんじゃないかなーと思う。