【きょうのわん公】ワンちゃん占いBOTを作りたい

## コーギーと暮らしたい日々
コーギーと暮らしたい妄想を膨らませながら日々を生きる今日この頃、少しでも自分のコーギー欲を満たす事ができないか・・・？
**そうだ！！コーギー画像を漁りまくる自分得なBOTを作ってやろう！**
と思い企画を立ててみました！

ということで今回はLINE BOTとNode-REDを使用して、大好きなコーギーやその他お気に入りのお犬達の画像を収集するLINE BOTを作成してみようと思います！またおまけでChatGPTも使ってみたいと思います！
今回の実装目標はこちらになります！

:::note info
**【実装目標】
・ 指定した犬種の画像をランダムで抽出してLINEに返信する
・ ChatGPTで今日の運勢の取得してLNEに送信する
・ 完全ノーコードで実装する**
:::

## 環境準備
今回使用した環境は以下の通りです。
・Node-RED（FlowForge）
・LINE BOT（Messaging API）
・ChatGPT
・[Dog API](https://dog.ceo/dog-api/)

## LINE BOTの実装開始
### 構成イメージ図
今回作成するLINE BOTの構成イメージは以下の通りです。
利用者がLINEから欲しい犬種を選択すると、選択された犬種の画像が返信され、その後ChatGPTが当日の占い結果を返信する流れとなります。

![スクリーンショット 2023-10-28 134659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/14180aac-7f02-b3f8-8946-3c5b2a41060c.png)

### 実装内容
実装したノードは以下の通りとなります。
え！複雑！！！と思ったあなた！私も思いました・・・・ですがノードを並べるのが下手なだけでやっている事は非常に簡単ですので、**ポイントを3点に絞って説明していきます。**

**■Node-RED画面**
![スクリーンショット 2023-10-28 154425.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/4b8fff3d-7b1b-e35c-cb50-589896214135.png)
```json:JSON
[{"id":"db421108b641cdeb","type":"Webhook","z":"89177bdf3679be85","name":"犬選択","url":"/webhook","x":70,"y":280,"wires":[["2cf4eb0436b3d7cb"]]},{"id":"63a90546a1fd01b2","type":"switch","z":"89177bdf3679be85","name":"コーギー画像検索","property":"payload.message","propertyType":"msg","rules":[{"t":"cont","v":"corgi","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":610,"y":100,"wires":[["68405b961c2fbb4d"],["3da6e63814a07a80"]]},{"id":"eccf2bff9bcb04d8","type":"http request","z":"89177bdf3679be85","name":"ループ処理","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://dog.ceo/api/breeds/image/random","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":610,"y":260,"wires":[["762fc2ca153197d4"]]},{"id":"68405b961c2fbb4d","type":"change","z":"89177bdf3679be85","name":"画像返却処理①","rules":[{"t":"move","p":"payload.message","pt":"msg","to":"payload2","tot":"msg"},{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.type","pt":"msg","to":"image","tot":"str"},{"t":"set","p":"payload.originalContentUrl","pt":"msg","to":"payload2","tot":"msg"},{"t":"set","p":"payload.previewImageUrl","pt":"msg","to":"payload2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":880,"y":260,"wires":[["c2802c49eec55e17","cc843dc55f2b0517"]]},{"id":"c2802c49eec55e17","type":"ReplyMessage","z":"89177bdf3679be85","name":"","replyMessage":"","x":1120,"y":260,"wires":[]},{"id":"2cf4eb0436b3d7cb","type":"switch","z":"89177bdf3679be85","name":"検索対象の犬種分岐","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"コーギー","vt":"str"},{"t":"eq","v":"ビーグル","vt":"str"},{"t":"eq","v":"ゴールデンレトリバー","vt":"str"},{"t":"eq","v":"柴犬","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":5,"x":260,"y":280,"wires":[["dfc496ae3b145461","63a90546a1fd01b2"],["dfc496ae3b145461","762fc2ca153197d4"],["dfc496ae3b145461","3044a28a4496d84a"],["dfc496ae3b145461","c2fd148cc282db86"],["2ac3548a76fd26a8"]]},{"id":"762fc2ca153197d4","type":"switch","z":"89177bdf3679be85","name":"ビーグル画像検索","property":"payload.message","propertyType":"msg","rules":[{"t":"cont","v":"beagle","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":610,"y":200,"wires":[["68405b961c2fbb4d"],["eccf2bff9bcb04d8"]]},{"id":"3044a28a4496d84a","type":"switch","z":"89177bdf3679be85","name":"ゴールデン画像検索","property":"payload.message","propertyType":"msg","rules":[{"t":"cont","v":"golden","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":600,"y":300,"wires":[["68405b961c2fbb4d"],["e5f2fffd54af77dc"]]},{"id":"492cd37c64054627","type":"PushMessage","z":"89177bdf3679be85","name":"メッセージ送信①","x":350,"y":180,"wires":[]},{"id":"dfc496ae3b145461","type":"template","z":"89177bdf3679be85","name":"検索処理待ち文","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"ちょっと待ってワン！","output":"str","x":160,"y":180,"wires":[["492cd37c64054627"]]},{"id":"7cd73ecf0c1ccdba","type":"PushMessage","z":"89177bdf3679be85","name":"メッセージ送信③","x":1210,"y":160,"wires":[]},{"id":"0145a178da7fcc78","type":"simple-chatgpt","z":"89177bdf3679be85","name":"ChatGPT","Token":"｛ChatGPTのアクセストークンを入力｝","Model":"","SystemSetting":"犬の口調で","functions":"","functionsType":"str","function_call":"auto","function_callType":"str","x":1040,"y":160,"wires":[["7cd73ecf0c1ccdba"]]},{"id":"cc843dc55f2b0517","type":"template","z":"89177bdf3679be85","name":"ChatGPT検索文","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"今日のてんびん座の占い教えて","output":"str","x":880,"y":160,"wires":[["0145a178da7fcc78"]]},{"id":"2ac3548a76fd26a8","type":"template","z":"89177bdf3679be85","name":"検索対象外文言","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"今日の運勢を占ってあげるから写真を選択してワン！","output":"str","x":300,"y":520,"wires":[["7d35a82b44da2786","5763c8905531b77f"]]},{"id":"14719b142b5502f5","type":"http request","z":"89177bdf3679be85","name":"ランダム犬種検索","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://dog.ceo/api/breeds/image/random","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":690,"y":520,"wires":[["02d837ebbfcaf618"]]},{"id":"7d35a82b44da2786","type":"delay","z":"89177bdf3679be85","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":500,"y":520,"wires":[["14719b142b5502f5"]]},{"id":"5763c8905531b77f","type":"PushMessage","z":"89177bdf3679be85","name":"メッセージ送信②","x":570,"y":580,"wires":[]},{"id":"02d837ebbfcaf618","type":"change","z":"89177bdf3679be85","name":"画像返却処理③","rules":[{"t":"move","p":"payload.message","pt":"msg","to":"payload2","tot":"msg"},{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.type","pt":"msg","to":"image","tot":"str"},{"t":"set","p":"payload.originalContentUrl","pt":"msg","to":"payload2","tot":"msg"},{"t":"set","p":"payload.previewImageUrl","pt":"msg","to":"payload2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":900,"y":520,"wires":[["c2802c49eec55e17"]]},{"id":"3da6e63814a07a80","type":"http request","z":"89177bdf3679be85","name":"ループ処理","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://dog.ceo/api/breeds/image/random","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":610,"y":160,"wires":[["63a90546a1fd01b2"]]},{"id":"e5f2fffd54af77dc","type":"http request","z":"89177bdf3679be85","name":"ループ処理","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://dog.ceo/api/breeds/image/random","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":610,"y":360,"wires":[["3044a28a4496d84a"]]},{"id":"d05a5269db5e470d","type":"http request","z":"89177bdf3679be85","name":"ループ処理","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://dog.ceo/api/breeds/image/random","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":610,"y":460,"wires":[["c2fd148cc282db86"]]},{"id":"c2fd148cc282db86","type":"switch","z":"89177bdf3679be85","name":"柴犬画像検索","property":"payload.message","propertyType":"msg","rules":[{"t":"cont","v":"Akita","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":580,"y":400,"wires":[["68405b961c2fbb4d"],["d05a5269db5e470d"]]}]
```

#### ポイント①：ループ処理
![スクリーンショット 2023-10-28 142814.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/a0aea22f-0a00-a9c9-8a62-87e16a3244d6.png)

まずは指定の犬種の画像を抽出する処理です。
Dog APIはランダムの犬の画像を返却するAPIであるため、**指定の犬種が取得できるまでAPIの実行を繰り返すループ処理を作成しました。（他の犬種部分も同じ処理で構成しております。）**

![スクリーンショット 2023-10-28 144427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/3fc84c88-305c-d198-ba62-75e3e4dffeaa.png)
![スクリーンショット 2023-10-28 144851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/1451cc58-937f-3f24-ac04-1a5ea8b2c9ec.png)

#### ポイント②：画像メッセージの返信処理
![スクリーンショット 2023-10-28 145127.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/d8f20d53-d9b5-33cd-a46a-67c3c976bab0.png)
次に画像メッセージの送信処理となります。
LINEmessagingAPIで画像を送信する場合、**受け取ったJSONデータからimage形に変換してから送信する必要があります。** そのため、changeノードを使用してDog APIから返却された値を加工していきます。

![スクリーンショット 2023-10-28 150549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/c2ec42c0-42a2-ab1c-2a6e-c48827ef991b.png)
![スクリーンショット 2023-10-28 150935.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/319038cd-fa4a-b4de-cc48-7b0e31f00391.png)

#### ポイント③：ChatGPTの結果をテキストメッセージの送信処理
![スクリーンショット 2023-10-28 151120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/d547c781-b9fe-d119-7f8f-21724368e675.png)

最後にChatGPTで占いを行う処理と、結果をテキストメッセージで送信する処理となります。
こちらはChatGPTで占いの実行命令を与えれば良いため、defaultノードに定型文を設定し、**ChatGPTノードとLINEPushノードを繋げるのみとなります。**

![スクリーンショット 2023-10-28 151800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/1901b6d8-1b2f-f8c2-3e1f-8c7a6ee0c905.png)
![スクリーンショット 2023-10-28 152227.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/443ecde4-2cea-31d8-8d81-af2c424abd25.png)
![スクリーンショット 2023-10-28 152515.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/8458129e-66fd-d12f-97c2-13040e0eb1dc.png)


**※その他のノードは他と同じ仕組みとなりますので説明は割愛します**


## LINE画面のリッチメニューを作成する
LINEから固定文字列を入力してもらうためにリッチメニューを作成します。
こちらは[リッチメニュー画像の作り方から設定方法まで徹底解説](https://line-sm.com/blog/howtomakerich-menus/)を参考に作成してすぐに完成しました。

**はい！かわいいー！**

![スクリーンショット 2023-10-28 160050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567275/cd365f71-2951-8fb9-42bc-7b160bba033b.png)

## 完成したLINE BOTを動かしてみる
ということで完成！！実際に動かしてみました！！
ループ処理部分で多少時間がかかりますが、想定通りかわいいお犬達の写真をゲットする事ができました！完全に私得なBOTの完成です！！！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">またシフトチェンジ！<br>愛犬家なのに犬と暮らせない自分の為、<br>可愛いお犬達が今日の運勢を占ってくれるLINE BOTを作りました！<br>あーーお犬かわいい！！！！<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a><a href="https://twitter.com/hashtag/LINEBOT?src=hash&amp;ref_src=twsrc%5Etfw">#LINEBOT</a><a href="https://twitter.com/hashtag/ChatGPT?src=hash&amp;ref_src=twsrc%5Etfw">#ChatGPT</a><a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%BC%E3%82%AE%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#コーギー</a><a href="https://twitter.com/hashtag/%E7%8A%AC%E5%A5%BD%E3%81%8D%E3%81%95%E3%82%93%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#犬好きさんと繋がりたい</a> <a href="https://t.co/CNrqdaApZB">pic.twitter.com/CNrqdaApZB</a></p>&mdash; oooookawa (@ooooooooookawa) <a href="https://twitter.com/ooooooooookawa/status/1718103160693415970?ref_src=twsrc%5Etfw">October 28, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 振り返り
今回の実装はノーコードをテーマにしていたため、functionノードなどのプログラムは使用しませんでしたが、それにより以下の通り、苦労した点や反省点なども見つかる結果となりました。

:::note warn
**・ ノード数が増えて全体のNode-RED構成が複雑になった
・ ループ処理の実装がうまくいかずに時間を要した
・ LINEのメッセージを複数送信するための実装がうまくいかずに時間を要した**
:::

一方でノーコードでもここまでそれっぽいものが作成できるのか！という発見もあり、他にもいろんなものに応用できそうだなと感じました。LINR BOT非常に楽しかったです！

最後までお読み頂きましてありがとうございました🐶

## 参考情報
https://qiita.com/mitoreterusuki/items/478272eb874e9b72c373

https://qiita.com/kakakaori830/items/52e52d969800de61ce28