【enebular】GeneralTalker APIを使ってLINEの雑談チャットボットを作ってみた

##作ったもの

雑談チャットボットを作ってみました。
というか、API使っただけですが・・・

これは、ゲームAI専門会社「モリカトロン」さんのGeneralTalker APIという会話APIを使ってます。
とてもスムーズな会話になっていて素晴らしいです。

![273030844_4837500389631790_7383600536049108668_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/34eec53a-0be1-96d6-89c0-344474bdaede.jpeg)

~~一応こちらで公開してますので、よかったらお友達になってください。~~
※無料枠はAPIリクエスト制限（1日100）があるので、非公開にしました。

##GeneralTalker API（モリカトロン）

数年前に、NTTドコモさんの雑談APIを使ってLINEのチャットボットを作ったのですが、ずっと放置していたら、いつの間にか有料化されていて、APIが使えなくなっていました。
そこで、他に代替の雑談APIはないか探しましたが、無料で簡単に使える雑談APIが見つかりません。

あきらめかけたところに、ゲームAIの会社のモリカトロンさんのAPIを発見しました。
[GeneralTalker APIを使ったLINE botの作り方](https://tech.morikatron.ai/entry/2021/06/07/192000)

APIの詳細は、Rakuten Rapid API　のサイトをご参照。
https://api.rakuten.net/morikatroninc-morikatroninc-default/api/generaltalker

1億5千万ペアの対話会話を学習させていて、語り合っている相手の過去の発言を記憶し会話の文脈を考えた受け答えをするそうです。

これは凄い。

さっそく、これを使って、チャットボットを作ります。

今回は、enebular でやってみました。


なお、すでにenebular や　LINE BOT の初期設定がすんだ前提で始めます。



enebular や LINE の登録や設定についてはこちらのサイトがとても参考になります。
[enebularでLINE Messaging APIを試してみる](https://qiita.com/ko2a/items/68911cdbaf221c42eb9a)

<br>

## ノードの全体像

enebular の環境でNode-REDで作りました。
（LINEのMessaging APIのノードがあるのは知ってますが、今回は使わなかったです）

[![Image from Gyazo](https://i.gyazo.com/73e022c30d9472171020e9473b5ef9c5.png)](https://gyazo.com/73e022c30d9472171020e9473b5ef9c5)


こちらをコピペでいけます。

```
[{"id":"8c7613b0.16829","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"fde5043b.745d78","type":"http in","z":"8c7613b0.16829","name":"(1)LINEからメッセージ受信","url":"/line","method":"post","upload":false,"swaggerDoc":"","x":160,"y":60,"wires":[["8fcf362e.00bae8"]]},{"id":"4ccb8a7b.647ea4","type":"http response","z":"8c7613b0.16829","name":"(3)LINEへ疎通確認","statusCode":"","headers":{},"x":550,"y":160,"wires":[]},{"id":"ebf012b5.d198d","type":"http request","z":"8c7613b0.16829","name":"(7)BOTの文章をLINE へ投稿","method":"POST","ret":"obj","paytoqs":false,"url":"https://api.line.me/v2/bot/message/reply","tls":"","persist":false,"proxy":"","authType":"basic","x":640,"y":380,"wires":[["31d1facd.068ae6"]]},{"id":"31d1facd.068ae6","type":"debug","z":"8c7613b0.16829","name":"念のための最後まで処理できたか確認(empty)","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":680,"y":500,"wires":[]},{"id":"8fcf362e.00bae8","type":"function","z":"8c7613b0.16829","name":"(2)LINEからの情報ゲット等","func":"// LINEサーバーからの情報をmsg.lineに退避させる\nmsg.line = msg.payload;\n\n// msg.payloadに送信されたメッセージ本体を入れる\nmsg.payload = msg.payload.events[0].message.text;\n\n// msg.payloadにトークンを入れる\nmsg.linetoken = \"LINEのチャネルアクセストークン\";\nreturn msg;","outputs":1,"noerr":0,"x":200,"y":160,"wires":[["4ccb8a7b.647ea4","1dd7b70e.056919","9fe3f63.ce71d08"]]},{"id":"e863d35.62a483","type":"http request","z":"8c7613b0.16829","name":"(5)GeneralTalker API（雑談AI）","method":"GET","ret":"obj","paytoqs":true,"url":"https://generaltalker.p.rapidapi.com/on_general/?bot_name={{{bot_name}}}&user_name={{{user_name}}}&user_msg_text={{{user_msg_text}}}&use_detect_user_info=true&save_only_positive_info=true&load_only_positive_info=true&use_change_topic=true","tls":"","persist":false,"proxy":"","authType":"basic","x":630,"y":260,"wires":[["f306a92b.8da2b8"]]},{"id":"f306a92b.8da2b8","type":"function","z":"8c7613b0.16829","name":"(6)BOTの文章を作成","func":"// 送信したい文字列をresultに退避させておく\nconst result = msg.payload;\n\n// LINEサーバーからの内容をpayloadに復元する\nmsg.payload = msg.line;\n\n// 返信メッセージをhttp requestの結果にする\nreplyMessage = result.response.res;\n\nvar post_request = {\n    \"headers\": {\n        \"content-type\": \"application/json; charset=UTF-8\",\n        \"Authorization\": \" Bearer \" +  msg.linetoken\n    },\n    \"payload\": {\n        \"replyToken\": msg.payload.events[0].replyToken,\n        \"messages\": [\n            {\n                \"type\": \"text\",\n                \"text\": replyMessage\n            }\n        ]\n    }\n};\n\nreturn post_request;","outputs":1,"noerr":0,"x":340,"y":380,"wires":[["ebf012b5.d198d"]]},{"id":"1dd7b70e.056919","type":"function","z":"8c7613b0.16829","name":"(4)GeneralTalker API（雑談AI）へ送る前処理","func":"\nuser_msg_text = encodeURIComponent(msg.payload) //エンコードする\n\nmsg = {\n \n \"bot_name\" : \"MyBot\", //なんでもいい\n \"user_name\" : msg.line.events[0].source.userId , // 各個人のLINEユニーク番号、ここを指定すれば過去の会話ともスムーズになるらしい\n \"user_msg_text\":user_msg_text, //ユーザーがチャットボットに投稿した内容\n \n  headers: {\n    'x-rapidapi-key': 'GeneralTalker APIキー',\n    'x-rapidapi-host': 'generaltalker.p.rapidapi.com',\n    useQueryString: true\n  },\n  \n  \"payload\": msg.payoad, //消えないようにここに避難　（もっといい方法ありそうだけど）\n  \"line\": msg.line,　　　 //消えないようにここに避難\n  \"linetoken\": msg.linetoken　　　 //消えないようにここに避難\n  \n};\n\nreturn msg;\n","outputs":1,"noerr":0,"x":270,"y":260,"wires":[["e863d35.62a483"]]},{"id":"9fe3f63.ce71d08","type":"debug","z":"8c7613b0.16829","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":580,"y":80,"wires":[]}]
```

<br>
##各ノードの説明

###(1) LINEからのメッセージ受信 (http in ノード)

メソッド：POST
URL: /line

[![Image from Gyazo](https://i.gyazo.com/0714497aded4966392d5283c1923b1c4.png)](https://gyazo.com/0714497aded4966392d5283c1923b1c4)


###(2) LINEからの情報ゲット等(functionノード)

```
// LINEサーバーからの情報をmsg.lineに退避させる
msg.line = msg.payload;

// msg.payloadに送信されたメッセージ本体を入れる
msg.payload = msg.payload.events[0].message.text;

// msg.payloadにトークンを入れる
msg.linetoken = "LINE チャンネルアクセストークン";

return msg;
```

###(3)LINE への疎通確認（http response ノード）

とくに何も入力しない。
でも、これがないと動きません。

[![Image from Gyazo](https://i.gyazo.com/7c86f0470c62d02673ce203e6c081322.png)](https://gyazo.com/7c86f0470c62d02673ce203e6c081322)


###(4)GeneralTalker APIへ送る前処理　（functionノード）

GeneralTalker API　に msg でヘッダー情報など渡すので、LINEの情報などを消えないようにしています。多分もっといい方法ありそうだけど、もう動いたのでヨシとします。

APIキーはRakuten Rapid API のサイトで入手できます。
https://api.rakuten.net/morikatroninc-morikatroninc-default/api/generaltalker

過去の会話のやりとりから自然な会話ができるらしいので、
user_name に、対話相手を特定するためにLINEのユニーク番号を入れてます。



```
user_msg_text = encodeURIComponent(msg.payload) //エンコードする

msg = {
 
 "bot_name" : "MyBot", //なんでもいい
 "user_name" : msg.line.events[0].source.userId , // 各個人のLINEユニーク番号、ここを指定すれば過去の会話ともスムーズになるらしい
 "user_msg_text":user_msg_text, //ユーザーがチャットボットに投稿した内容
 
  headers: {
    'x-rapidapi-key': 'APIキー',
    'x-rapidapi-host': 'generaltalker.p.rapidapi.com',
    useQueryString: true
  },
  
  "payload": msg.payoad, //消えないようにここに避難　（もっといい方法ありそうだけど）
  "line": msg.line,　　　 //消えないようにここに避難
  "linetoken": msg.linetoken　　　 //消えないようにここに避難
  
};

return msg;

```

###(5)GeneralTalker API（http request ノード）

クエリパラメータを使ってます。
これももっとスムーズな方法ができそう。
でも、いろいろ試してみたけど、これ以外で正常動作しなかったので、このやり方を採用しました。

- メソッド：　GET
- URL　：　
https://generaltalker.p.rapidapi.com/on_general/?bot_name={{{bot_name}}}&user_name={{{user_name}}}&user_msg_text={{{user_msg_text}}}&use_detect_user_info=true&save_only_positive_info=true&load_only_positive_info=true&use_change_topic=true
- 「msg.payload をクエリパラメータに追加」にチェック
- 「認証を使用」にチェック、種別を Basic認証
-  出力形式：　JSONオブジェクト

[![Image from Gyazo](https://i.gyazo.com/5243fd3c12d45ed1f699a468e62292b2.png)](https://gyazo.com/5243fd3c12d45ed1f699a468e62292b2)


###(6)BOTの文章を作成（functionノード）

```
// 送信したい文字列をresultに退避させておく
const result = msg.payload;

// LINEサーバーからの内容をpayloadに復元する
msg.payload = msg.line;

// 返信メッセージをhttp requestの結果にする
replyMessage = result.response.res;

var post_request = {
    "headers": {
        "content-type": "application/json; charset=UTF-8",
        "Authorization": " Bearer " +  msg.linetoken
    },
    "payload": {
        "replyToken": msg.payload.events[0].replyToken,
        "messages": [
            {
                "type": "text",
                "text": replyMessage
            }
        ]
    }
};

return post_request;
```


### (7)BOTの文章をLINE へ投稿

以下のように入力
[![Image from Gyazo](https://i.gyazo.com/fff5f388e3b65b0ebc3fb7af658f53d1.png)](https://gyazo.com/fff5f388e3b65b0ebc3fb7af658f53d1)


<br>
##Heroku へデプロイ

こちらにまとめました。
[enebular で作成したLINEボットを Herokuにデプロイする](https://qiita.com/tatsuya1970/items/cafe8967958e81e23457)

<br>
以上です。
<br>