Excelの数式として使えるChatGPT関数。 ChatGPT function that can be used as an Excel formula

# やったこと
Excelで、質問に対する回答をAIのChatGPTに答えてもらう関数を作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/990728c9-5e11-df09-2ac8-195b40e78591.png)
応用すれば、セルに貼った文章の要約、ポジネガ判定、キーワード抽出も自由自在にできそう。精度の問題はあれども。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/f5299b86-0648-ccfc-77bf-8d42c55b33ea.png)

Excelなので、こういう表形式と相性が良いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/68343e0f-1289-7fe4-ef3f-a1b835d5e93e.png)

# 手順
【注意！】本記事の手順でAPIを大量に実行すると、お金がかかります。（2023年1月19日現在、18$分の無料枠があります）

## （準備）ChatGPTのAPIのキーを取得する
ChatGPTのAPIを利用できるように、ChatGPTのサイトでユーザー登録して、
APIのキーをもらう。
手順はこちら↓
https://qiita.com/k1morikawa@github/items/5482939eb49fb70207a5

準備ができたら新しいExcelファイルでVBA編集画面に移ります。

## VBAマクロの基本的な作り方
このあたりを参照してください。
https://www.sejuku.net/blog/73163

## VBAの参照設定
APIとやり取りするために、以下の参照設定を行います。
参照設定については、このあたりを見てください。
https://www.sejuku.net/blog/76520

参照するライブラリは、以下の２つです。
・Microsoft Scripting Runtime
・Microsoft Forms 2.0 Object Library
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/4fd0afd9-b8a0-5f3f-7fbe-889a661f011d.png)

## ChatGPTとJsonでやりとりするために、JsonConverterをダウンロードして読み込む
ChatGPTのAPIとやり取りするためには、
質問文などのデータをJSON形式に変換してやり取りする必要があります。
そこでデータをJSON形式に変換（Convert）してくれるVBAパッケージ、
JsonConverterを利用します。

手順はこちら↓
VBAでJSON形式のデータを扱うに便利なVBA-JSON
https://javeo.jp/vba-json/

このようにJsonConveterが標準モジュール内に入れば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/e80d1b2a-3c3e-6499-5c1b-e36df534b4cf.png)

## VBAコード（gpt-3.5-turboバージョン）
（2023年3月追記、より新しいgpt-3.5-turboのAPIが公開されたので、追加しました。）
VBAコードは以下のとおりです。もっと良い書き方があればご指摘ください。
コード内の{API_KEY}は、「準備」で取得したAPIキーに置き換えてください。（sk-で始まる文字列）
```vb
Function gpt(mytext)
  
  Application.Volatile False
  
  '入力テキストが無ければ終了
  If mytext = "" Then
      gpt = "何かテキストを入力してください。"
      Exit Function
  End If
  
  'APIとやり取りするためのデータをDictionary型で作る（後でJSONに変換）
  Dim JsonObject As Object
  Set JsonObject = New Dictionary
  Dim JsonObject_mini As Object
  Set JsonObject_mini = New Dictionary
  JsonObject.Add "model", "gpt-3.5-turbo"
  JsonObject_mini.Add "role", "user"
  JsonObject_mini.Add "content", mytext
  JsonObject.Add "messages", Array(JsonObject_mini)
  
  'API実行
  Dim objHTTP As Object
  Dim res As Object
  
  'API実行
  Set objHTTP = CreateObject("msxml2.xmlhttp")
  objHTTP.Open "POST", "https://api.openai.com/v1/chat/completions", False
  objHTTP.setRequestHeader "Content-Type", "application/json"
  '■■■■■API_KEYを置き換える必要あり■■■■■
  objHTTP.setRequestHeader "Authorization", "Bearer " & "{API_KEY}"
  objHTTP.send JsonConverter.ConvertToJson(JsonObject)
  
  'レスポンスコードのチェック(正常)
  If objHTTP.Status <> 200 Then
      gpt = "error"
      Exit Function
  End If
  
  'レスポンスJSONを辞書型に変換する
  Set res = ParseJson(objHTTP.responseText)
  'レスポンスの中から質問への回答を取り出して、戻り値とする
  gpt = Replace(Trim(res("choices")(1)("message")("content")), vbCrLf, "")
End Function
```
## 使い方
Excelのセル上で、例えば
```vb
=gpt("幸せってなんですか")
```
と入力すれば、数秒後に回答を得られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/02dfa0a6-bd82-c5e1-c97b-bf9f729ae895.png)

# 感想
ChatGPTはジャンルによっては嘘をつくので、怖いです。
またAPIの実行速度も1件5～10秒ほどかかるため、実用には工夫が必要です。
あと、ChatGPTは連続的に会話してなんぼ、という面もあるので、1件だけのやり取りでは本領が発揮できていない気もしました。

# 過去ログ
## VBAコード（text-davinci-003バージョン）
（2023年3月追記、より新しいgpt-3.5-turboのAPIが公開されたので、こちらは古いバージョンです。）
VBAコードは以下のとおりです。もっと良い書き方があればご指摘ください。
コード内の{API_KEY}は、「準備」で取得したAPIキーに置き換えてください。（sk-で始まる文字列）

```vb

Function chatgpt(mytext)
  
  '入力テキストが無ければ終了
  If mytext = "" Then
      chatgpt = "何かテキストを入力してください。"
      Exit Function
  End If
  
  'APIとやり取りするためのデータをDictionary型で作る（後でJSONに変換）
  Dim JsonObject As Object
  Set JsonObject = New Dictionary
  JsonObject.Add "model", "text-davinci-003"
  JsonObject.Add "prompt", mytext
  JsonObject.Add "temperature", 0
  JsonObject.Add "max_tokens", 2048

  Dim objHTTP As Object
  Dim res As Object
  
  'API実行
  Set objHTTP = CreateObject("msxml2.xmlhttp")
  objHTTP.Open "POST", "https://api.openai.com/v1/completions", False
  objHTTP.setRequestHeader "Content-Type", "application/json"
  '■■■■■API_KEYを置き換える必要あり■■■■■
  objHTTP.setRequestHeader "Authorization", "Bearer " & "{API_KEY}"
  objHTTP.send JsonConverter.ConvertToJson(JsonObject)
  
  'レスポンスコードのチェック(正常)
  If objHTTP.Status = 200 Then
      response = objHTTP.responseText
  Else
      chatgpt = "error"
      Exit Function
  End If
  
  'レスポンスJSONを辞書型に変換する
  Set res = ParseJson(response)
  'レスポンスの中から質問への回答を取り出して、戻り値とする
  Set Choices = res("choices")
  chatgpt = Replace(Trim(res("choices")(1)("text")), vbCrLf, "")  
End Function
```

# おわり
おわりです。お疲れ様でした。