ChatGPT × LINE Bot × Make ノーコードで対話できるChatBotを作成する

https://protoout.connpass.com/event/280991/

本資料はこちらの体験会で使用したハンズオン資料を改定したものになります。
[LINE Developers](https://developers.line.biz/ja/)のアカウント設定や[OpenAIのAPI_key](https://platform.openai.com/account/api-keys)、[make(integromat)](https://eu1.make.com/)のアカウント作成などは実施をお願いします。

https://developers.line.biz/ja/

https://platform.openai.com/account/api-keys

https://eu1.make.com/

::: note alert
本記事にはLINE Messaging APIのCHANNEL_ACCESS_TOKENなど記載されていますが、本来は悪用を防ぐために、漏洩には十分注意してください。
:::

## 1. 今回の目標

- **LINEを通じてChatGPTのAPIを叩いて、リプライが返ってくるLINE Botをつくる**
- **APIを叩くときのプロンプトを調整し、想定した返答を引き出す**

以上、2点が実施できることを目標としています。

## 2. おうむ返しBotの作成

**まずはリプライメッセージを送るLINE Botの基本となるおうむ返しBotを準備します。**

### 2-1. 目標となる形
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/8f979b0c-ed70-b40c-0298-81355e957615.png" width=75%>

### 2-2. モジュールの設定

#### 2-2-1. Watch Events

- 最初に表示されている⊕をクリックして表示されるモーダルで、`line`を検索。表示される`Watch Events`をクリックします

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/8dd25ebe-5d3e-9fa7-ba48-0927403e11f4.png" width=75%>
>
> Watch Eventsを選択

- Webhookを設定します。`Create Webhook`ボタン、`Create a connection`ボタンを順次クリックし、LINE Developersより取得したCHANNEL ACCESS TOKENを貼り付けてください

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/e1297d9c-2dc5-2ee7-dfb5-5274d005b66b.png" width=75%>
> 
> `Create a webhook`をクリック

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/077568db-2c18-88d6-d5ec-25c181a8f300.png" width=75%>
>
> `Create a connection`を選択

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/e103669b-217a-4c45-782f-d53b7a9867c6.png" width=75%>
>
> Channel Access Tokenの欄にLINE Developers側で取得したトークンを張り付けて`Save`ボタンを押す

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/d815fd47-6ce2-f48c-e712-a697608a6be3.png" width=75%>
>
> Connectionの欄に新しい接続が表示されるので`Save`ボタンをクリック

- LINE Developers側には、下画像の`Copy address to clipboard`の部分からコピーしたWebhook_URLを貼り付けてください
- Webhook_URLの有効化も忘れずにチェックしてください

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/904e5e7a-0d06-9257-fee2-0b3437bb35be.png" width=75%>
>
> `Copy address to clipboard`ボタンをクリックしてURLをコピー

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/6e70abf1-6845-21d9-2a41-97d446af4fbf.png" width=75%>
>
> LINE Developersがわの画面でWebhook URLの欄にコピーしたURLを張り付け

#### 2-2-2. Send a Reply Message

- LINEモジュールの横にある〇をクリックして別のモジュールを追加。同じくLINEをクリックして、出てくる`Send a Reply Message`をクリックします

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/d84dbe77-ce5b-ca84-8409-e102c83eed0b.png" width=75%>
>
> マウスホバーして出てくるAdd another module をクリック

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/5ac3cfb6-cc61-e737-722b-dbc8d0ec6ef4.png" width=75%>
>
> LINEモジュールを選択

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/600edb29-d757-cda1-b8bd-060207d1bfcf.png" width=75%>
>
> Send a Reply Messageを選択

- Reply TokenとTextの部分を画像の通りに設定。利用者側からMessaging APIを通して送られてきた情報より、Reply Tokenとテキスト情報を抜き出すイメージです

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/fffb804b-8fc2-492e-3e2a-e3a0d0c2a315.png" width=75%>
>
> Reply Tokenの欄は`1.Events[` `]: Reply Token`。Textの欄は`1.Events[` `]: Message.Text`を選択

- Run onceを押した状態でメッセージを送ると全く同じメッセージが返ってくるおうむ返しBotとなります
- 常に有効化（つまりデプロイされた状態に）するには`scheduling`を`ON`にして、時計マークをクリックして出てくる`Run scenario`を`immediately`にした状態で保存すれば良いです

![スクリーンショット 2023-04-23 23.05.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/f9cb648e-2095-06eb-79c3-364e96c7b902.png)

## 3. OpenAI モジュールの組み込み

**OpenAIのAPI（gpt-3.5-turbo）を叩いて、返ってきたテキストをリプライするLINE Botを作成します。**

### 3-1. 目標となる形

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/b2361cf5-ae1c-1672-eff8-504be3ba0e9a.png" width=75%>

### 3-2. Create a Completion

- `Connection`の`Add`ボタンをクリックしてAPIの設定をします
- モジュールは画像の通り、`Create a Completion`、`gpt-3.5-turbo`を選んでください
- 発行したAPIキーとアカウントのOrganization IDを其々コピーペーストします

https://platform.openai.com/settings/organization/general
> Organization IDはこちらURL

- MessagesはRoleを`User`、Message Contentのところには`Events[]:Message.Text`を入力してください。これでLINEに入力した言葉でChatGPTのAPIを叩くことができます

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/bde11fc2-8fff-4d31-7679-9c6137e4373b.png" width=75%>
>
> `Create a connection`ボタンをクリック

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/32ad6b5b-96ad-748d-73bb-91575b143adb.png" width=75%>
>
> API keyと Organization IDをコピーペーストして`Save`

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/10705313-e982-faf3-c520-d6d529a2cb53.png" width=75%>
>
> Select MethodはCreate a Chat Completion、Modelはgpt-3.5-turbo、MessagesのRoleをUser、Message Contentを`1. Events[` `]: Message.Text`

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/9c5d3675-85d2-f3a5-dc57-b14ca8629484.png" width=75%>
>
> Max Tokens に0を入力して`OK`ボタンをクリック

### 3-3. Send a Reply Message

- 先ほどはMessagesのTextのところに送られてきたテキストをそのまま返すようにしていましたが、今回は`Choices[]:Message.Content`を入力します。これが、ChatGPTのAPIから返ってきたメッセージとなります

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/c78a6f45-1717-3c59-9a8e-262564b480a8.png" width=75%>
>
> Messages のTextを`Choices[` `]:Message.Content`。これまでの設定が正しくできていればOpenAIの選択肢がSend a Reply Messageモジュールに表示されるようになります

実行するとChatGPTと単体の会話ができます。

![スクリーンショット 2023-04-23 23.13.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/9f318d61-f3a3-b2c2-1437-ca7af74174cb.png)

## 4. プロンプトの設定

ChatGPTに特定の役割を与え、自分の想定した返答を引き出す技術がプロンプトの調整となります。詳細は下記リンク先[Prompt Engineering Guide](https://www.promptingguide.ai/jp)を参考にしてみてください。

https://www.promptingguide.ai/jp

今回は料理研究家の役割を与えて、食材からメニュー提案をしてもらいます。

### Create a Completion

- MessagesのItem1はRoleを`System`、Message Contentにプロンプトを入力します
- Item2は先ほどと同様、RoleをUserとし、Message ContentはLINEのテキストです

![スクリーンショット 2023-04-23 23.26.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/6936d8c9-409e-8dc6-3b36-80617fe422eb.png)

### 通常のChat GPTの返答

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/7a650443-ac1d-897b-de4d-a93eb82b1ac0.png" width=75%>


### プロンプトを与えた場合の返答

![スクリーンショット 2023-04-23 23.26.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/68fd3969-e9ff-6eb6-cd7e-d2db5c6f377e.png)


## 応用　LINE Bot上で会話を行う

:::note warn
以下、Data Stores部分に関する動作は2024.05.09時点で確認しておりません。コメント欄にあるスプレッドシートを利用した方法を推奨しますが、Data Stores, Data structuresの紹介として記述自体は残しておきます
:::

ここまでで作成したLINE Botは一問一答形式にのみ対応しており、会話ができません。それは、データベース上に会話を保存していないためであり、APIを叩いて得られるテキストに文脈を反映させるためには、これまでの会話ログと合わせて入力することが必要となります。

### 通常のChat GPTの返答

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/c5fb7e1e-d64e-1ee1-985b-6920adc488a9.png" width=75%>

### 単純にAPIを叩いた場合の返答

![スクリーンショット 2023-04-23 23.16.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/8e3d2e7b-ddd0-7deb-f66b-d60c33769423.png)

## Data Stores, Data structuresの設定

- 今回はデータベースとして、Makeの機能としてある`Data Stores`を利用します。
- データベースの構造は`Data stucture`のメニューから画像の通り設定してください。userIdをtext、valueをcollection（参照配列）で設定します。

![スクリーンショット 2023-04-23 23.34.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/ba5f46b0-2e60-a1a6-7aab-c07ae37f23fd.png)

![スクリーンショット 2023-04-23 23.34.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/0c8d9ddb-9c51-afc8-f183-e475af318d90.png)

![スクリーンショット 2023-04-23 23.34.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/fa4d7a84-84e9-f2fb-7e74-22be2e4ed831.png)

::: note
gpt-3.5-turboのAPIは

```json
[
    {"role": "system", "content": "role_sample"},
    {"role": "user", "content": "Hello!"},
]
```
のような形式でmessagesのデータを受け取りますので、データベースのvaluesはこの形式に合わせています。
さらに、ユーザーごとの会話ログを識別するために、NameにLINEの`userId`を保存していきます。
:::

## 会話ログの保存

### 目標となる形

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/fd8f2139-7f7e-4fbd-6611-4ff7483b51f1.png" width=75%>

### Add/replace a record（１つめ）

- LINEから受け取った`userId`とテキストデータを`user`からの情報として保存します。
![スクリーンショット 2023-04-25 6.55.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/7128210d-f991-a5dc-4c71-eeb5679ee95d.png)


### Add/replace a record（2つめ）

- ChatGPTのAPIから受け取ったリプライを`assistant`からの情報として保存します。
- LINEの`userId`も一緒に保存することで、利用者を識別します。
![スクリーンショット 2023-04-25 6.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/d62995a2-91af-5723-d055-b79e41c98481.png)

**実際にLINEからメッセージを送ると、LINEのuserIdと一連の会話ログが保存されます。**

![スクリーンショット 2023-04-25 7.02.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/0bce02e5-f9c2-133a-9bb3-202009c65459.png)


## 会話ログをデータベースから呼び出しAPIを叩く

### 目標となる形

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/67e905be-563f-26b2-2e76-54d5be9cea28.png" width=75%>

### search records

- 今回は1往復分の会話を取得し、送信されたメッセージと合わせてChatGPTのAPIを叩きます
- 受け取ったLINEのuserIdとData storeの`userId`が一致するデータを取得しますので、FilterをuserId, `Events[];Source.User ID`に設定します
- 1往復分の会話、つまり会話ログ2つを取得するのでLimitに2を設定します
![スクリーンショット 2023-04-25 7.05.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/f2943916-e84e-9476-d759-22cbc66706de.png)

### Array aggregator

- Data storeは一致したデータをイテレーターとして返しますので、Array aggregatorで配列のデータに直します
![スクリーンショット 2023-04-25 7.07.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/e7473e3d-5cd7-54b0-2eab-a459d49895de.png)

### Create Completion

- 取得したデータを合わせて、ChatGPTのAPIを叩きます
- Item 1が前提条件として設定するプロンプト
- Item 2に前回Userが送信したメッセージとして、Array Aggregatorで生成した配列データの1つめ
- Item 3に前回Assistantから受け取ったメッセージとして、Array Aggregatorで生成した配列データの2つめ
- Item 4に今回LINEから受け取ったメッセージをそれぞれ設定します
- Array[]の番号に注意してください

![スクリーンショット 2023-04-25 7.15.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/b4a04837-9224-4fc2-695b-49445c5113b0.png)

![スクリーンショット 2023-04-25 7.15.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/5ef379ed-7ead-8f0e-d98e-e480a2e80992.png)



## エラーハンドリング：初めてメッセージを送信する方への対応

### 目標となる形

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/62a8f712-b2c7-47c4-8898-b50fcee50c48.png" width=75%>

- 前回設定したものでは、初めてメッセージを送信する方からのデータを受け取った場合、エラーが発生してしまいます。ですので、APIを叩くところでエラーハンドリングを実行します

### エラーハンドリングの設定

- Array aggregatorが生成されない（初めて利用するため過去のデータがない）場合、分岐させてプロンプトとLINEのメッセージを用いてAPIを叩くように設定します
![スクリーンショット 2023-04-25 7.20.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/950838ca-67ef-846b-36ce-bba7b7a0bb6c.png)


以上で、一通り会話できるChat Botの作成は完了です。