はじめてのChatGPTとCodeWhisperer

巷で噂の生成系AI、せっかくだからPythonでもチャレンジしてみた。

[こちらの記事](https://dev.classmethod.jp/articles/openai-api-chat-python-first-step/)を参考に、あとは[Amazon CodeWhisperer](https://aws.amazon.com/jp/codewhisperer/)（これ自身も生成系AIサービスである）に手伝って貰ったり、ChatGPT自身に聞いたりしながら試行錯誤してみた結果を残しておく。

### 下準備
- pip3でモジュールをインストールする。
```shell:
pip3 install openai
```

- [OpenAIのサイト](https://chat.openai.com/)にサインインして、APIキーを取得する。詳細は[こちら](https://auto-worker.com/blog/?p=6988)を参照。

- 環境変数にAPIキーを食わせる（今回は`.zshrc`に入れた）。なお他の全てのキーと同様、APIキーの取り扱いにはご注意を。

- IDE（Visual Studio Code）に、CodeWhispererを入れておく。AWS Builder IDも必要。詳細は[こちら](https://zenn.dev/yuta28/articles/codewhisperer-tutorial)の記事を参照。なお、CodeWhispererはついでに試してみたかっただけで、なくてもChatGPTコードは動きます。

```shell
> cat << EOS >> ~/.zshrc
# OpenAI
export OPENAI_API_KEY="sk-{文字列}"
EOS
> . ~/.zshrc 
```

## コード

### 最初のバージョン

単に質問するだけのバージョン。ほぼ[こちら]((https://dev.classmethod.jp/articles/openai-api-chat-python-first-step/))の写経だが、一応関数にして引数を受け取れるようにはしてみた。また、ChatGPT自身に聞いた際提案された通り、whileループでユーザー入力を延々受け付けるようにしている。
ただし、質問の回答は保持していないので「会話」にはなっていない。

```python:chatgpt-sample1.py
'''
質問に返すだけ。コンテキストは保持しない
'''
import os
import openai

# APIキーの設定
openai.api_key = os.environ["OPENAI_API_KEY"]

def chat(tone, prompt):
    # ChatGPTにプロンプトを渡して回答を得る
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": tone}, # 回答方法などの設定
            {"role": "user", "content": prompt},  # 質問内容
        ],
    )
    
    # 回答を返却
    return response.choices[0]["message"]["content"]

if __name__ == "__main__":
    # 初期値
    tone = "広島弁で話して"

    # q（またはQ）と入力するまで会話を続ける
    while True:
        prompt = input("ご質問は？> ")
        if prompt.lower() == "q":
            print("終了します。ありがとうございました。")
            break
        else:
            answer = chat(tone, prompt)
            print(answer)
```

### 最終バージョン

[本家](https://chat.openai.com/)と同様、会話を成立させたかったので、色々調べたりデバッグしたりしながらコードを追加。

```python:chagpt-sample2.py
'''
コンテキストを保持して会話を成立させる
'''
import os
import openai

# APIキーの設定
openai.api_key = os.environ["OPENAI_API_KEY"]

def chat(tone, context, prompt):
    # ChatGPTにプロンプトを渡して回答を得る
    response = openai.ChatCompletion.create(
        model = "gpt-3.5-turbo",
        messages = [
            {"role": "system", "content": tone},  # 回答方法などの設定
            {"role": "assistant", "content": context},  # 前の会話のコンテキスト
            {"role": "user", "content": prompt},  # 質問内容
        ],
    )
    answer = response.choices[0]["message"]["content"]
    next_context = answer

    # 回答とコンテキストを返却
    return answer, next_context

if __name__ == "__main__":
    # 初期値
    tone = "広島弁で話して"
    context = ""

    # q（またはQ）と入力するまで会話を続ける
    while True:
        prompt = input("ご質問は？> ")
        if prompt.lower() == "q":
            print("終了します。ありがとうございました。")
            break
        else:
            answer, next_context = chat(tone, context, prompt)
            print(answer)
            context = next_context
```

## 実行
動かしてみる。
![スクリーンショット 2023-05-14 18.30.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/37eb42fc-bd0b-e7da-f852-c5ccd968f6e1.png)

## CodeWhispererの場合
CodeWhispererを使ってコード生成を依頼してみた場合のコードは、以下のような感じになる（途中まで）。
コメント箇所を入力すると、推奨コードが生成される。グレーアウトされている箇所が生成されたコードで、確定すると次の推奨コードが出てきて、の繰り返しで出来上がっていく。
![スクリーンショット 2023-05-14 18.39.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/b76672e6-fb29-1809-ca74-087a42308b44.png)

CodeWhispererについては、今回はとりあえず動かしてみた程度。後述の通り、ChatGPTに関するコードはそのままでは動かなかったので、もっとも、これは本家が出力したコードも同じだったが。
コメントに書く内容を捻れば、かなり楽ができそうな気配は感じた。

## まとめ

実に簡単。そして楽しい。

もう一つ考えさせられたのは、調べ方の変化。以前はググってどうこうだったが、今回は**ChatGPTにコードを貼り付けて「これに対話機能を追加するには？」と入力してサンプルコードを取得し、動くようにトライアンドエラーしながら書き変える**という形を試してみたが、案外使えた。これは確かに生産性上がりそう。特にコードの場合、それらしいサンプルが手に入ることは（自分のような初学者には特に）重要だ。

ただし、ChatGPTもCodeWhispererも、生成されたコードがそのまま動くとは限らなかった（先の記事にも記載されていたが、`model = "gpt-3.5-turbo"` ではなく `engine = "davinci"`となったりする。他にも色々）。
コードに限らず、生成系AIの回答に不正確な内容が含まれるとはよく言われることだが、ここは今後どんなに精度が上がろうとも、人間が最終チェックをすべきところなんだろうとは思った。

とりあえずはあれこれ試したり学んだりしつつ、生成系AIとの付き合い方を考えていきたい。