PythonとGAS（GoogleAppsScript）でchatGPTとの対話記録をGoogleスプレッドシートに記録する

# はじめに
　皆さんchatGPT使ってますか。chatGPTの熱は収まることを知らず、APIを叩いた経験がある方も多いのではないでしょうか。chatGPTのAPIはどんなサービスに入れても、面白い化学反応をもたらしますよね。しかし、若干の欠点（？）のようなものもあるような気がします。
　
　それは、**対話記録を残しにくい**ところです。Web版はログに残るので、過去の記録も簡単に見れるんですけどね……。

　先輩にそのことを相談してみると「GASとかならいけるんじゃない？」とのこと。なるほど、やってみよう。

# 下準備
　とりあえず今回は簡潔なもので挑戦しました。まず、PythonでchatGPTのAPIを使った対話のプログラムを用意します。
~~~Python:gptapi.py
import openai

# APIキーの設定
openai.api_key = "APIkey"

Question = input("chatGPTへの質問を書いてください:")

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "system", "content": "敬語を使わずに話してください"},
        {"role": "user", "content": Question},
    ],
)
GPTResponse = response.choices[0]["message"]["content"].strip()

print(GPTResponse)
~~~
　APIキーはご自身のものをお使いください。　
　ここはあまり説明しなくてもよいかもしれないですね。試しに、このプログラムを走らせてみると、こんな感じになります。
~~~Pytnon:ターミナル
chatGPTへの質問を書いてください:chatGPTって何ですか

chatGPTとは、OpenAIが開発した人工知能の一つで、対話形式でコミュニケーションを行うことができます。
GPTはGenerative Pretrained Transformer(生成型事前学習トランスフォーマー)の略であり、自然言語処理において高い精度を誇るニューラルネットワークモデルの一種です。
chatGPTは、あたかも人との会話をするかのようなリアルな対話を行うことができます。
~~~
　現在、ターミナルに表示されているこいつらをGAS（GoogleAppsScript）を使って、スプレッドシートに書き込みを行っていきます。（今回は簡潔なプログラムでやっていますので、このくらいならWeb版でよくない？との突っ込みはご容赦を）

# 想定している流れ
　こんな感じの流れをイメージしてます。
```mermaid
graph TD;
    Pythonで質問と生成した文章をJson形式で送る-->送られてきたJsonをGASで処理する;
    送られてきたJsonをGASで処理する-->Googleスプレッドシートに質問と生成した文章を記録する;

```
　それではやっていきましょー。
# GASサイドの処理
　最初にお手持ちのGoogleアカウントから新規のスプレッドシートを作成してください。その後、拡張機能→AppsScriptを選択すると、AppsScriptのエディタが表示されると思います。拡張機能にAppsScriptがない場合は、Googleドライブから新規でインストールしてください（詳しくは[こちら](https://matsukiyoshi.com/gas-howto/)）。
### スプレッドシートに値を書き込む
　まず、スプレッドシートに値を書き込むコードを作成します。以下のコードを、AppsScriptにコピペして実行してみてください。（ちなみにGASはjavascriptです。投稿主はjavascriptをしっかりと学んではいないませんが、なんやかんやできます）
~~~GAS:
function doPost(e){
    const question = "どうも";
    const gptresponse = "こんにちわ";

    // データを加工しありスプレッドシートを操作したり
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName("シート1"); // シート名は適宜変更してください
    //シートのデータを取得
    const lastRow = sheet.getLastRow();
    const lastColumn = sheet.getLastColumn();
    const range = sheet.getRange(1, 1, lastRow || 1, lastColumn || 1);
    const values = range.getValues();

    //時間を取得
    const now = new Date();
    const timestamp = now.toLocaleString();
  
    let isExist = false;
    for (let i = 0; i < values.length; i++) {
      if (values[i][1] === question) {
        isExist = true;
        const cell1 = sheet.getRange(i + 1, 1);
        cell1.setValue(timestamp);
        const cell2 = sheet.getRange(i + 1, 2);
        cell2.setValue(question);
        const cell3 = sheet.getRange(i + 1, 3);
        cell3.setValue(gptresponse);
        break;
      }
    }

    if (!isExist) {
      const newRow = [timestamp, question, gptresponse];
      sheet.appendRow(newRow);
    }
}
~~~
　おそらく、初回実行時は権限の関連で、警告が出ると思います。その場合は、[こちら](https://auto-worker.com/blog/?p=609)の通り進めてもらえると問題ないです。
　さて、もう一度実行してみると、「実行した時間/どうも/こんにちわ」と表示されていると思います。またquestionとgptresponseの値を変えてみると、新たな行に追加されていることがわかります。
### 値をJsonで受け取ったデータにする
　先ほどはquestionとgptresponseの値を「どうも」と「こんにちわ」にしていましたが、これをJsonで受け取ったデータにします。
~~~
    //  パラメータでJsonを受け取り、パース
    const jsonString = e.postData.getDataAsString();
    const jsonData = JSON.parse(jsonString);
    const question = jsonData.questions;
    const gptresponse = jsonData.responses;
~~~
　jsonData.questionsはJsonから受け取ったchatGPTへの質問、jsonData.responsesはchatGPTからの返答となります。
### GASサイドの全体コードとデプロイ
　GAサイドのコードの全体はこのようになります。
~~~
// POSTメソッドで実行される
function doPost(e){
    //  パラメータでJsonを受け取り、パース
    const jsonString = e.postData.getDataAsString();
    const jsonData = JSON.parse(jsonString);
    const question = jsonData.questions;
    const gptresponse = jsonData.responses;

    //スプレッドシートの情報を取得
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName("シート1"); // シート名は適宜変更してください
    //シートのデータを取得
    const lastRow = sheet.getLastRow();
    const lastColumn = sheet.getLastColumn();
    const range = sheet.getRange(1, 1, lastRow || 1, lastColumn || 1);
    const values = range.getValues();

    //時間を取得
    const now = new Date();
    const timestamp = now.toLocaleString();
  
    //スプレッドシートへの書き込み
    let isExist = false;
    for (let i = 0; i < values.length; i++) {
      if (values[i][1] === question) {
        isExist = true;
        const cell1 = sheet.getRange(i + 1, 1);
        cell1.setValue(timestamp);
        const cell2 = sheet.getRange(i + 1, 2);
        cell2.setValue(question);
        const cell3 = sheet.getRange(i + 1, 3);
        cell3.setValue(gptresponse);
        break;
      }
    }
    if (!isExist) {
      const newRow = [timestamp, question, gptresponse];
      sheet.appendRow(newRow);
    }
}
~~~
　ここまでくればGASサイドでやることは残り２つです。
①スプレッドシート→共有から、一般的なアクセスを「リンクを知っている全員」に変更してください。
②先ほどのコードをデプロイします。
　デプロイ→新しいデプロイ→種類の選択→ウェブアプリ→アクセスできるユーザー→全員→デプロイ
この順番でやってもらえば問題ないです。また最後のデプロイを押した際に、表示されるデプロイID、ウェブアプリURLは各自保存しておいてください。今回はURLを使います。
　完了を押せばGASサイドは完成です。次はPythonサイドです。
# Pythonサイドの処理
　Pythonサイドは冒頭提示しましたプログラムに継ぎ足していきます。早速ですが、コードの全体はこんな感じ。
~~~Json.py
import openai
import json
import requests

# APIキーの設定
openai.api_key = "APIkey"
url = "先ほどコピーしたURLをここに入れてください"

Question = input("chatGPTへの質問を書いてください:")

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "system", "content": "敬語を使わずに話してください"},
        {"role": "user", "content": Question},
    ],
)
GPTResponse = response.choices[0]["message"]["content"].strip()
print(GPTResponse)

#GPTへの質問と返答をJson形式にする
data = {
	"questions": Question,
	"responses" : GPTResponse
}
#PostメソッドでURLにJsonデータを送る
r = requests.post(url, data=json.dumps(data))
print(r)
~~~
　chatGPTへの質問を"questions"、返答を"responses"としてJson形式で、先ほどのURLに送っています。それでは実際に動かしてみましょう。
# 実践
　先ほどのJson.pyを起動させます。コンソール上ではこんな感じです。
~~~
chatGPTへの質問を書いてください:鎌倉時代について教えて

鎌倉時代は、日本の中世時代の一つで、1185年から1333年までの期間を指します。この時代は、源頼朝によって幕府が開かれ、武士の時代として知られています。
鎌倉幕府は、近隣の地域の守護をまかされ、彼らはその地域の支配者となりました。このことが、日本の中央集権的な政治システムから地方分権の政治システムへの転換をもたらしました。
また、鎌倉時代には、武士の倫理とされる「武士道」が生まれ、日本の武士風の文化が根付きました。  
鎌倉時代の文化には、茶道や歌舞伎などの芸術が含まれており、武士に支持されました。また、鎌倉時代には、禅宗や浄土宗などの仏教が普及しました。
鎌倉時代は、日本の歴史上、重要な時期の一つで、日本の文化・社会・政治的な変化をもたらしました。
~~~
　これがスプレッドシートに記録されていればOKです。
　スプレッドシートを開いてみると……
![chatGPT対話画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293324/58406732-758b-6f0e-bc0e-77550464e50a.png)
　しっかりと、スプレッドシートに記録されていますね。成功です。
# まとめ
　ということで、chatGPTで生成した文章をGoogleスプレッドシートに記録するプログラムを試しました。今回はシンプルなプログラムを走らせましたが、例えば、（言語は変わってしまいますが）話題になっていたこのような記事にも応用できます。

https://qiita.com/uezo/items/7ff1566f05c0a1c74a46

　GASを扱うのは初めてでしたが、とても良い経験になりました。

# こちらもどうぞ
chatGPTでこんなこともしてます。

https://qiita.com/ema_kurida/items/7b6f567adea2aca7aa81

また機会がありましたら是非。
読んでいただきありがとうございます。