2023年11月のアップデートで、OpenAI社はChatGPTを利用したAIアシスタントを構築できる Assistants APIを追加しました。
2023年12月現在はまだベータ版ですが、このAPIを利用すると、ChatGPT Web版で利用できた、Code Interpreterの機能をプログラム上で実行させることができます。 Web版のCode InterpreterではプログラムをChatGPT上で動かし、結果として生成されたファイルを受け取ることができました。当然このAPIを使っても、ファイルを生成させることができます。
ただ、では生成したファイルはどうやったらダウンロードできるのでしょう?
返ってくるメッセージの本文にダウンロードのパスが記載されるのではないの?と思われるかもしれません。しかし、私が試しにダミーデータを生成する指示を与えるプログラムを作成してみたところ、返ってきたメッセージの本文は次のようなものでした:
ダミーデータを10件生成し、CSV形式で出力しました。以下のリンクからダウンロードできます。
[ダウンロード dummy_data.csv](sandbox:/mnt/data/dummy_data.csv)
sandbox:/mnt/data/
って言われてもどこやねん、となってしまいますね。。
ということで自分が詰まったので、その対処法をメモとしてブログに残しておきます。
結論
- 結果として返ってくるメッセージデータに、生成したファイルのID(
file_id
)が含まれているので、これを取り出す files.content
メソッドでfile_id
を引数として指定することでファイルを取得する
これだけの話ではありますが、以下、実際のコードを交えて説明します。
まずはAssistants APIの基本的な処理のおさらい
Assistants APIの基本的な処理の流れは以下の通りです。 - アシスタントAIを作成 - アシスタントAIに指示するスレッドを作成 - 結果のデータを取得
以下、簡単なダミーデータを生成するコードのサンプルを示します。
import requests
import time
from openai import OpenAI
# アシスタント作成処理
client = OpenAI()
assistant = client.beta.assistants.create(
name="My Assistant",
instructions="あなたはデータ処理を行うAIアシスタントです。命令に従ってCSVを生成してください。",
tools=[
{"type": "code_interpreter"},
],
model="gpt-4-1106-preview"
)
# スレッド作成・実行
thread = client.beta.threads.create()
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="「品物」「単価」のフィールドを持つダミーデータを10件生成してください。品物の名前は日本語の果物名として、エントリ内でユニークとしてください。単価は日本円として、100円〜1000円の範囲で設定してください。結果はCSV形式で出力してください。"
)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id
)
# 結果が生成される(Statusがcompletedになる)まで待つ
while run.status != 'completed':
run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
print(run.status)
time.sleep(5)
# 出力メッセージの取得
output_messages = client.beta.threads.messages.list(
thread_id=thread.id
)
print(output_messages.data) #debug用
client.beta.assistants.create()
でアシスタントを作成、続いてclient.beta.threads.create()
でスレッドを作成。スレッド内で指示するメッセージをclient.beta.threads.messages.create()
で定義して、client.beta.threads.runs.create()
で実行しています。
途中の while run.status != 'completed'
から始まる処理は、スレッドの実行ステータスを確認して、ChatGPTの処理が終わるまで待つ処理です。ステータスがcompleted
になると、出力結果が取り出せるようになります。ここでは出力結果をoutput_messages
に格納しています。
ファイル情報の取得
出力結果を格納したoutput_messages.data
内に含まれるデータは以下のような感じです。
[ThreadMessage(id='xxx', assistant_id='xxx', content=[MessageContentText(text=Text(annotations=[TextAnnotationFilePath(end_index=118, file_path=TextAnnotationFilePathFilePath(file_id='xxx'), start_index=79, text='sandbox:/mnt/data/dummy_fruits_data.csv', type='file_path')], value='ダミーデータを10件生成し、CSV形式で出力しました。以下のリンクからダウンロードできます。\n\n[ダウンロード dummy_data.csv](sandbox:/mnt/data/dummy_data.csv)'), type='text')], created_at=1703952985, file_ids=['file-xxx'], metadata={}, object='thread.message', role='assistant', run_id='run_xxx', thread_id='thread_xxx'), (以下省略)]
value
に含まれるのが回答の本文ですが、先ほども説明したようにこの回答に含まれるパスはダウンロードが可能なパスではありません。
実際に重要なのは、このデータ内に別に含まれているfile_ids
というフィールド内のIDとなります。このIDを指定してclient.files.content(file_id)
を実行することで、実際のファイルのデータを取得することができます。以下、上記を踏まえた先ほどのコードの続きです。output_messages.data
内では複数のファイルIDが含まれる可能性があるため、それらを抽出しfor
文で順次処理しています。
# 出力ディレクトリの指定
output_dir = "results"
# 生成されたファイルのID情報をメッセージから抽出
file_ids = [
file_id
for m in output_messages.data
for file_id in m.file_ids
]
print(file_ids) #debug用
# 取得したファイルIDをもとにローカルにファイルを書き込み
for file_id in file_ids:
output_path="{}/{}.csv".format(output_dir, file_id)
write_file_data = client.files.content(file_id)
file_data_bytes = write_file_data.read()
with open(output_path, "wb") as file:
file.write(file_data_bytes)
おわりに
というわけで、OpenAI assistant APIを利用したファイルのダウンロードの方法の紹介でした。説明したようにメッセージの本文にあるパス情報が有効ではない点にやや戸惑いますが、ベータ版ですので今後改善するかもしれません。このAPIでファイルを生成・ダウンロードする機能は非常に便利だと思いますので、試してみてはいかがでしょうか。ではでは。