GPT-4o-miniでGoogleColaboratoryのノートブックを生成する

## 概要

GPTのコードインタプリタ機能では、コードを生成・実行しデータ分析やチャート作成を行ってくれます。
大変画期的ですが、実際に使う場合は生成されたコードに間違いがないかチェックを行い、必要に応じてコードを修正するケースが多いのではないかと思います。
修正する際は「GPTが出力したコードを自身の環境にコピペして修正する」という手順を踏むのが普通だとは思いますが、せっかくならもっと便利に使いたい･･･。そう考えていたのですが
「CSVファイルを渡したら良い感じにデータ前処理と基礎分析を行い、それらの過程をipynb形式のノートブックとして結果をまとめることができたら修正が捗りそう」とふと思いつきました。

GoogleColaboratory上でGeminiが使えるようになったりノートブックと生成AIの連携は進んでますがノートブックそのものを生成するというのはあまり事例がない？ように思ったので、
個人的に実現できないか試しにスモールな実験をしてみることにしました。


### イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/16bf8f49-39bd-ad4a-29b6-443e439356c2.png)

### 結果

ちょいちょい間違いはあれどプロトタイプとしては使えそうなものが作れました。([結果はこちら](#生成したノートブックをgooglecolaboratoryにアップロード))
データ分析者におなじみのノートブックで出力されるのでGoogleColaboratoryにアップロードすればそのまま確認、修正ができます。分析結果が日本語で書き込まれるのもLLMの強みを活かせている感じもあります。

今回はダミーデータがシンプルなので複雑なデータを渡したときにどうなるか検証する必要がありますが、より高性能なモデルを使用したりプロンプトを工夫することで精度向上の余地があり、期待値は高いという印象です。

## 実験内容

### ダミーデータの準備
適当に作成したダミーデータを用います。
なんとなくコールセンターの問い合わせログっぽいデータを作成しました。
データはランダムで欠損や不正値などを発生させています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/469dbef7-f6aa-39b7-b0d2-bfeb66ba5cdb.png)


### CSVを分析してノートブックを出力するコード
モデルはGPT-4o-miniを利用します。プロンプトは下記を使用しました。
「データもらったけど定義書ないし、とりあえずデータ眺めてみて特徴掴んでみよう」みたいなシチュエーションを想定しています。

```ruby:プロンプト
以下のテーマに基づいてCSVを確認し、データ補正および分析を行ってください。
1.データの説明（何を示すデータか）
2.各カラムの説明（カラムの役割、最大値、最小値、最頻値、欠損値や不正値の状況)
3.欠損または不正な値は補正、または補正が難しい場合はレコードを除外してください。除外したデータについては報告を行ってください
4.補正後のデータを元にビジネス上のリスクや問題点を分析してください。分析結果は可視化を行った上で説明してください
データ補正、分析につかったPythonコードと日本語で解説した分析結果をGoogle Colabにアップロード可能なipynb形式にまとめて出力してください。
```

下記Pythonコードを実行してノートブック生成を行います。

```ruby:openaiのクライアントライブラリをインストール
!pip install openai
```
```ruby:APIキーの設定
### APIキーの設定
import openai
import os
from google.colab import userdata
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
```
```ruby:GPT-4o miniのCode Interpreterでipynb出力
from openai import OpenAI
client = OpenAI()

def upload_csv(file_path):
    with open(file_path, "rb") as file:
        response = client.files.create(
            file=file,
            purpose="assistants"
        )
    return response.id

def gen_first_analyze_ipynb(file_id):
    assistant = client.beta.assistants.create(
        model="gpt-4o-mini",
        tools=[{"type": "code_interpreter"}],
        instructions="""
          あなたは優秀なデータ分析エンジニアです。
        """,
        tool_resources={
          "code_interpreter": {
            "file_ids": [file_id]
          }
        }
    )
    thread = client.beta.threads.create()
    run = client.beta.threads.runs.create_and_poll(
      thread_id=thread.id,
      assistant_id=assistant.id,
      instructions="""
          以下のテーマに基づいてCSVを確認し、データ補正および分析を行ってください。
          1.データの説明（何を示すデータか）
          2.各カラムの説明（カラムの役割、最大値、最小値、最頻値、欠損値や不正値の状況)
          3.欠損または不正な値は補正、または補正が難しい場合はレコードを除外してください。除外したデータについては報告を行ってください
          4.補正後のデータを元にビジネス上のリスクや問題点を分析してください。分析結果は可視化を行った上で説明してください
          データ補正、分析につかったPythonコードと日本語で解説した分析結果をGoogle Colabにアップロード可能なipynb形式にまとめて出力してください。
      """
    )
    if run.status == 'completed': 
      messages = client.beta.threads.messages.list(
        thread_id=thread.id
      )
      return messages
    else:
      return run

id = upload_csv("sample_csv.csv")
messages = gen_first_analyze_ipynb(id)
print(messages)
```
```ruby:ipynbファイルのIDを取得する
ipynb_file_id = ""
cont_dict = messages.model_dump() 
msg_list = cont_dict.get("data")
for msg in msg_list:
    content = msg.get("content")
    for cont in content:
      text = cont.get("text")
      if text:
        annotations = text.get("annotations")
        for ann in annotations:
          file_path = ann.get("file_path")
          if file_path:
            ipynb_file_id = file_path.get("file_id")
            print(ipynb_file_id)
```
```ruby:ipynbファイルを書き込みしてダウンロード
from google.colab import files
file_data = client.files.content(ipynb_file_id)
file_data_bytes = file_data.read()

with open("./export.ipynb", "wb") as file:
    file.write(file_data_bytes)

files.download("./export.ipynb")
```


### 生成したノートブックをGoogleColaboratoryにアップロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/ed7af5d2-d5ca-7708-ab60-350fca2f7857.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/1beaf7e7-109f-f63a-464d-4b232ff48304.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/10c26403-c47d-5554-1045-b6920bc66edf.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71286/991fb858-c651-3ee8-7d0d-8fdf1ade57aa.png)

それらしいものが表示されました。
内容としてはファイルパスさえ修正すれば一通りエラーもなくコードは動きました
ただし描画されたグラフが文字化けしていたり、欠損値が見当たらないと言っているのに、その後欠損を処理していたりするなど怪しい箇所もいくつかありました。
とはいえ大枠としては大体あってるので、ここから修正する前提のプロトタイプとしては良さそうです。