OpenAIのAPIを使ってChatGPTに1週間の夕食の献立を考えてもらう

## はじめに
株式会社トラストバンクでフロントエンドエンジニアをしている飯島（@iijima0226）です。
この記事は トラストバンクAdvent Calender 2023 の16日目の記事です。

最近チーム内でChatGPTを活用して個人開発をしているという話をよく聞くようになりました。
自分は今まで積極的にChatGPTを使ってはこなかったのですが、流石にそろそろ触っておかないとまずいかなと思い今回ChatGPTを使い何か作ってみることにしました。

## 題材について
さて、ChatGPTで何を作ろうかとを悩んでいた時、ちょうど「1週間の夕食の献立を考えるのが地味に面倒」という話を妻から聞きました。
これはちょうど良い題材かもしれないと思い早速ChatGPTで1週間の夕食を提案してもらえるようにしようと取り掛かりました。

作る内容としては下記のような仕様で作ることにしました。
* 主菜・副菜を提案してもらう
* 月曜日~金曜日の献立を提案してもらう
* レパートリーは大体決まっているのでその中から組み合わせて提案してもらう
* LINEのトーク上で提案してもらう

「ChatGPTのサイトを開くのが面倒」ということだったので、OpenAIのAPIを使用してLINEからChatGPTを使うようにしました。

## OpenAIの設定
1. アカウントの作成
1. secretkeyの発行
1. 支払い方法の設定
※ 支払い方法を設定しておかないとAPI使用時にエラーになります。

詳細な設定方法については下記記事の「[OpenAIの設定](https://zenn.dev/teppei6969/articles/chatgpt-hands-on#1.-openai-%E3%81%AE%E8%A8%AD%E5%AE%9A)」がとても参考になります。

https://zenn.dev/teppei6969/articles/chatgpt-hands-on#1.-openai-%E3%81%AE%E8%A8%AD%E5%AE%9A

## LINE Messaging API の設定
1. LINE Business IDのアカウントを作成
1. LINEアカウントでログイン
1. 新規プロバイダーを作成
1. 新規チャンネルを作成
1. チャンネルアクセストークンを発行

詳細な設定方法については下記記事の「[LINE Messaging API の設定](https://zenn.dev/teppei6969/articles/chatgpt-hands-on#2.-line-messaging-api-%E3%81%AE%E8%A8%AD%E5%AE%9A)」がとても参考になります。

https://zenn.dev/teppei6969/articles/chatgpt-hands-on#2.-line-messaging-api-%E3%81%AE%E8%A8%AD%E5%AE%9A

## GASの設定
LINEで入力されたメッセージをGASで受け取りOpenAIのAPIに渡し、OpenAIから返却されたメッセージをGASでまたLINEに送ります。
1. コードの記述
1. トークンの設定
1. デプロイ

コードはこんな感じです。

```js
function doPost(e) { 
  const props = PropertiesService.getScriptProperties()
  const event = JSON.parse(e.postData.contents).events[0]
  let userMessage = event.message.text

  const requestOptions = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer "+ props.getProperty('OPENAI_APIKEY')
    },
    "payload": JSON.stringify({
      "model": "gpt-3.5-turbo",
      "messages": [{"role": "user", "content": userMessage}]
    })
  }
  const response = UrlFetchApp.fetch("https://api.openai.com/v1/chat/completions", requestOptions)
  const responseText = response.getContentText();
  const json = JSON.parse(responseText);
  const text = json['choices'][0]['message']['content'].trim();

  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + props.getProperty('LINE_ACCESS_TOKEN'),
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': event.replyToken,
      'messages': [{
        'type': 'text',
        'text': text,
      }]
    })
  })
}
```

デプロイ後に発行されるURLをLINEのMessage APIのWebhook URLに設定すれば設定完了です。

詳細な設定方法については下記記事の「[GASでボットのプログラムを用意](https://qiita.com/daigo_38/items/f5b329364e177a340bbb#gas%E3%81%A7%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E7%94%A8%E6%84%8F)」を参考にしてください。

https://qiita.com/daigo_38/items/f5b329364e177a340bbb#gas%E3%81%A7%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E7%94%A8%E6%84%8F

## 動作確認
この段階でLINEからOpenAIのAPIを使用してChatGPTが使えるようになっているので動作確認をしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326291/597d12e7-abeb-0ac5-4c0b-9812e843809f.png)
LINE上でChatGPTが返信してくれるボットを作ることができました。

## ChatGPTに役割を与える
GASの```requestOptions```に設定していた```messages```で```role```を指定できるので、LINEのメッセージに対してどのように振る舞ってほしいかを設定していきます。
```js:
{"role": "system", "content": `
  #役割
  あなたは夕食の献立（主菜と副菜）の提案と作り方のサポートをするためのチャットボットです。以下の内容を学習し、60文字以内で明るく返答してください。

  #条件
  * 献立を聞かれたら下記の形式で答えること。
    主菜：〇〇
    副菜：〇〇
    ※週で聞かれた場合は曜日を先頭に追加する
  * 依頼されるまで献立の提案しないこと
  * 「今週」や「1週間」の献立を聞かれた場合は月曜日から金曜日までの献立を考えてください。
  * 1週間の主菜と副菜が被らないようにする
`}, 
```
上記のように```role```を追加して再度GASをデプロイし、LINEのWebhook URLを更新します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326291/fd40ddaf-9e7e-7a8d-e1b4-a1f8223a2911.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326291/aaace716-26ff-f253-bb84-d541a5a3b482.png)

決まった形式で夕飯を提案してくれるようになりました。

## レパートリーの中から献立を作ってもらえるようにする
スプレットシートに提案して欲しい献立をまとめてその中から提案してもらうようにします。
登録する主菜と副菜は下記の通りです。
| 主菜 | 副菜 |
|:-:|:-:|
| 唐揚げ  | きゅうりのごま油和え  |
| 麻婆豆腐 | ピーマンのおかか和え  |
| カレー  | 厚揚げの煮物  |
| ガリバタチキン  | ニラ玉  |
| 酢豚  | 白菜とツナの旨煮  |

GASに下記のコードを追加
```js
const ss = SpreadsheetApp.openByUrl('スプレットシートのURL');
const main = ss.getSheets()[0];
const side = ss.getSheets()[1];

const mainRange = main.getRange('A2:A6');
const sideRange = side.getRange('A2:A6');

const mainValue = mainRange.getValues().flat();
const sideValue = sideRange.getValues().flat();
const mainValueString = mainValue.join(', ');
const sideValueString = sideValue.join(', ');
```
OpenAPIの```message```も下記のように変更
```js
"messages": [
    {"role": "system", "content": `
      #役割
      あなたは夕食の献立（主菜と副菜）の提案と作り方のサポートをするためのチャットボットです。以下の内容を学習し、60文字以内で明るく返答してください。
    
      #条件
      * 献立を聞かれたら下記の形式で答えること。
        主菜：〇〇
        副菜：〇〇
        ※週で聞かれた場合は曜日を先頭に追加する
      * 依頼されるまで献立の提案しないこと
      * 「今週」や「1週間」の献立を聞かれた場合は月曜日から金曜日までの献立を考えてください。
      * 1週間の主菜と副菜が被らないようにする
      * 主菜は${mainValueString}の中から選ぶ
      * 副菜は${sideValueString}の中から選ぶ
    `}, 
    {"role": "user", "content": userMessage}
]
```
実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326291/b54dd94c-edd1-acac-9121-2cc07b5d4b11.png)
登録した主菜と副菜で献立を提案してくれるようになりました。

## 終わりに
今回はOpenAIのAPIを使ってLINEからChatGPTに夕食の献立を提案してもらえるチャットボットを作ってみました。
OpenAIのAPIとLINEの連携はいろいろな記事があったので思ったよりもサクッと作れました。
今後は材料や作り方も登録できるようにして夕食の提案と一緒に必要な材料も返してくれるような形にしようかなと思います。

トラストバンクでは、一緒に働く仲間を募集中です。

https://www.wantedly.com/companies/trustbank/projects