OpenAI APIのAssistants APIを使用して、ファイルのやり取りを含むアシスタントを作成してみた。
こんちには。
データアナリティクス事業本部 機械学習チームの中村(nokomoro3)です。
今回は、OpenAI APIのAssistants APIを使用して、ファイルのアップロードやダウンロードなどのやり取りを含むアシスタントを作ってみたいと思います。
Code Interpreterとは
Code Interpreterはサンドボックス化された実行環境でPythonコードを記述し、実行することができます。
Assistants APIを使用してこのCode Interpreterが有効なアシスタントを作成することができます。
このツールは、多様なデータやフォーマットのファイルを処理し、データやグラフの画像を含むファイルを生成でき、 アシスタントが自身が実行に失敗するコードを生成した場合、コードの実行が成功するまで別のコードの実行を試みるなど、ある程度自律的に動作をすることができます。
Assistants APIを使用してCode Interpreterを使う方法は以下に記載されています。
また、私も過去に以下の記事を書いています。
Assistantにファイルを渡す
AssitantはCode Interpreterなどを使用する際に、ファイルからデータを読み込むことができます。
これは、大量のデータをアシスタントに提供したい場合や、ユーザが分析用に自分のファイルをアップロードできるようにしたい場合に便利です。
ファイルの渡し方としては、Assistantレベルの渡し方、Threadレベルの渡し方などがあります。
ファイルのサイズは最大512MBまでで、.csv
や.json
、.pdf
などの拡張子に対応しています。
対応しているファイルのMIME typesは以下を参照ください。
Assistantからファイルを受け取る
APIのCode Interpreterは、イメージやCSV、PDFの生成など、ファイルの出力も行います。
Code Interpreterでファイルが出力されると、レスポンスのfile_idでこのファイルの中身をAPI経由でダウンロードできます。
from openai import OpenAI client = OpenAI() image_data = client.files.content("file-abc123") image_data_bytes = image_data.read() with open("./my-image.png", "wb") as file: file.write(image_data_bytes)
またファイルのリンクは、メッセージ上は別の文字列で表現されているため、ユーザに公開可能なリンクに上記のファイルをダウンロードして配置して、公開可能なリンクでメッセージを置き換える必要があります。
以下の[Download Shuffled CSV File](sandbox:/mnt/data/shuffled_file.csv)
の部分が該当の置き換えるべき対象です。こちらには、start_indexとend_indexを使ってアクセスすることができます。
{ "id": "msg_3jyIh3DgunZSNMCOORflDyih", "object": "thread.message", "created_at": 1699073585, "thread_id": "thread_ZRvNTPOoYVGssUZr3G8cRRzE", "role": "assistant", "content": [ { "type": "text", "text": { "value": "The rows of the CSV file have been shuffled and saved to a new CSV file. You can download the shuffled CSV file from the following link:\n\n[Download Shuffled CSV File](sandbox:/mnt/data/shuffled_file.csv)", "annotations": [ { "type": "file_path", "text": "sandbox:/mnt/data/shuffled_file.csv", "start_index": 167, "end_index": 202, "file_path": { "file_id": "file-oSgJAzAnnQkVB3u7yCoE9CBe" } } // ...
詳細は後述しますが、以下もご参照ください。
使ってみた
初期設定
openaiライブラリをインストールします。今回はopenai==1.10.0
を使用します。
pip install openai
ライブラリのインポートは以下です。
from openai import OpenAI from openai.types.file_object import FileObject import time import pathlib
発行したAPIキーを設定し、クライアントをインスタンス化します。
api_key = "{発行したOPENAI APIキー}" client = OpenAI( api_key=api_key )
APIキーの発行方法は以下を参照ください。
ファイル登録
まずはAssistantに参照させるファイルを登録します。
ローカルフォルダにcsvファイルを準備しておきます。ファイル自体は以下のレポジトリから拝借致しました。
ファイル登録のコードは以下です。
files = [] for file_name in [ "jaffle-shop/raw_customers.csv", "jaffle-shop/raw_orders.csv", "jaffle-shop/raw_payments.csv" ]: file = client.files.create( file=open(file_name, "rb"), purpose='assistants' ) files.append(file)
実行後に登録済みのファイル情報を確認してみます。
files: list[FileObject] = files for file in files: print(file.model_dump_json(indent=2)) # { # "id": "file-NjPcqnSI1rcFIrGkMz83DoNb", # "bytes": 1302, # "created_at": 1708665885, # "filename": "raw_customers.csv", # "object": "file", # "purpose": "assistants", # "status": "processed", # "status_details": null # } # { # "id": "file-nYt31owJ3APz6jaTNmRJ0gRG", # "bytes": 2723, # "created_at": 1708665886, # "filename": "raw_orders.csv", # "object": "file", # "purpose": "assistants", # "status": "processed", # "status_details": null # } # { # "id": "file-qdS80m8mXAy8xnzV9CqlJ7se", # "bytes": 2560, # "created_at": 1708665886, # "filename": "raw_payments.csv", # "object": "file", # "purpose": "assistants", # "status": "processed", # "status_details": null # }
Assistant作成
Assistantを作成します。
file_idsに登録したファイルのIDリストを渡します。またコードを実行させるために、toolsにCode Interpreterを設定します。
assistant = client.beta.assistants.create( name="cm-nakamura-assistant-2024-02-23", tools=[{"type": "code_interpreter"}], model="gpt-4-turbo-preview", file_ids=[file.id for file in files] ) print(assistant.model_dump_json(indent=2)) # { # "id": "asst_H24X1ae9Pdx7Ufceqdkj5GVa", # "created_at": 1708665918, # "description": null, # "file_ids": [ # "file-NjPcqnSI1rcFIrGkMz83DoNb", # "file-nYt31owJ3APz6jaTNmRJ0gRG", # "file-qdS80m8mXAy8xnzV9CqlJ7se" # ], # "instructions": null, # "metadata": {}, # "model": "gpt-4-turbo-preview", # "name": "cm-nakamura-assistant-2024-02-23", # "object": "assistant", # "tools": [ # { # "type": "code_interpreter" # } # ] # }
Thread作成
Assistantとやり取りするためのThreadを作成します。
thread = client.beta.threads.create() print(thread.model_dump_json(indent=2)) # { # "id": "thread_naDHVrafHHDXYjfifmrlkbJc", # "created_at": 1708665932, # "metadata": {}, # "object": "thread", # "tool_resources": [] # }
メッセージの投入
こちら側のAssistantに対する依頼をThreadのメッセージとして投入します。
(この時点ではAssistantの処理はまだ実行されません)
client.beta.threads.messages.create( thread_id=thread.id, role="user", content="raw_payments.csvから各payment_method毎のamountの総和を求めてそれをcsvファイルにしてください。" )
Threadのメッセージの中身を確認してみます。
messages = client.beta.threads.messages.list(thread_id=thread.id) print(messages.model_dump_json(indent=2)) # { # "data": [ # { # "id": "msg_RZqCf6cKGOaTPuXmHsLxMyKn", # "assistant_id": null, # "content": [ # { # "text": { # "annotations": [], # "value": "raw_payments.csvから各payment_method毎のamountの総和を求めてそれをcsvファイルにしてください。" # }, # "type": "text" # } # ], # "created_at": 1708665958, # "file_ids": [], # "metadata": {}, # "object": "thread.message", # "role": "user", # "run_id": null, # "thread_id": "thread_naDHVrafHHDXYjfifmrlkbJc" # } # ], # "object": "list", # "first_id": "msg_RZqCf6cKGOaTPuXmHsLxMyKn", # "last_id": "msg_RZqCf6cKGOaTPuXmHsLxMyKn", # "has_more": false # }
runの作成
runを作成することで、Assistantの処理を実行することができます。
run = client.beta.threads.runs.create( thread_id=thread.id, assistant_id=assistant.id, ) print(run.model_dump_json(indent=2)) # { # "id": "run_ZSPs8As0Vh4RvvyYwEtkrA3t", # "assistant_id": "asst_H24X1ae9Pdx7Ufceqdkj5GVa", # "cancelled_at": null, # "completed_at": null, # "created_at": 1708665964, # "expires_at": 1708666564, # "failed_at": null, # "file_ids": [ # "file-NjPcqnSI1rcFIrGkMz83DoNb", # "file-nYt31owJ3APz6jaTNmRJ0gRG", # "file-qdS80m8mXAy8xnzV9CqlJ7se" # ], # "instructions": null, # "last_error": null, # "metadata": {}, # "model": "gpt-4-turbo-preview", # "object": "thread.run", # "required_action": null, # "started_at": null, # "status": "queued", # "thread_id": "thread_naDHVrafHHDXYjfifmrlkbJc", # "tools": [ # { # "type": "code_interpreter" # } # ], # "usage": null # }
ru作成直後は"status": "queued"
となっていることが分かります。
実行待ち
runのステータスを確認しながら完了を待ちます。以下がステータスを確認するためのコードです。
def check_status(thread_id: str, run_id: str): """ステータスをチェックする""" run = client.beta.threads.runs.retrieve( thread_id=thread_id, run_id=run_id ) print(f"{run.status=}") if run.status == "completed" or run.status == "failed": return True else: return False
10秒単位で完了をチェックします。
while True: # 状態をチェック if check_status(thread_id=thread.id, run_id=run.id): print("completed.") break print("waiting...") # ステータスが完了状態になるまで一定時間待機 time.sleep(10) # run.status='in_progress' # waiting... # run.status='in_progress' # waiting... # run.status='in_progress' # waiting... # run.status='in_progress' # waiting... # run.status='in_progress' # waiting... # run.status='in_progress' # waiting... # run.status='completed' # completed.
レスポンスの確認
完了後、Assistantが作成したレスポンスはメッセージの内容から確認します。
分かりやすいようにロール名とテキストのみを抽出しています。
messages = client.beta.threads.messages.list(thread_id=thread.id, order="asc") # print(messages.model_dump_json(indent=2)) for message in messages.data: print(f"{message.role}: {message.content[0].text.value}\n") # user: raw_payments.csvから各payment_method毎のamountの総和を求めてそれをcsvファイルにしてください。 # # assistant: ファイル`raw_payments.csv`が存在しないため、エラーが発生しています。アップロードされたファイルを確認して、該当するファイルを処理するようにします。アップロードされたファイル名を確認し、それに応じて処理を行います。 # # assistant: アップロードされたファイルは以下の三つですが、正しいファイル名が指定されていませんでした。 # # - `/mnt/data/file-NjPcqnSI1rcFIrGkMz83DoNb` # - `/mnt/data/file-nYt31owJ3APz6jaTNmRJ0gRG` # - `/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se` # # これらのファイルの中で、`raw_payments.csv`に相当するものを探し、該当する操作を行います。まず、これらのファイルの内容を確認します。 # # assistant: `raw_payments.csv`に相当するファイルは `/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se` です。このファイルには、支払い方法 (`payment_method`) ごとに、金額 (`amount`) が記載されています。 # # このファイルを用いて各支払い方法ごとの金額の総和を計算し、結果を新たなCSVファイルに保存します。 # # assistant: 各支払い方法ごとの金額の総和を計算し、その結果をCSVファイルに保存しました。結果は以下のリンクからダウンロードできます: # # [total_amount_by_payment_method_correct.csv](sandbox:/mnt/data/total_amount_by_payment_method_correct.csv)
ファイル名が登録時に指定できていなかったため、該当ファイルがどれか判断するところから実行されていることがわかります。
また結果にファイルが含まれる場合、ファイルの中身自体は開発者がAPI経由で取得してユーザに公開できる場所に配置し、元のテキストをそのリンクに置き換える必要があります。
そのための必要な情報は、以下のannotationsにレスポンスとして含まれています。
print(messages.data[-1].content[0].text.model_dump_json(indent=2)) # { # "annotations": [ # { # "end_index": 168, # "file_path": { # "file_id": "file-mWILO7iIBIyGnqmvfCADjXSl" # }, # "start_index": 108, # "text": "sandbox:/mnt/data/total_amount_by_payment_method_correct.csv", # "type": "file_path" # } # ], # "value": "各支払い方法ごとの金額の総和を計算し、その結果をCSVファイルに保存しました。結果は以下のリンクからダウンロードできます:\n\n[total_amount_by_payment_method_correct.csv](sandbox:/mnt/data/total_amount_by_payment_method_correct.csv)" # }
ダウンロードにはfile_idを使用します。
result = messages.data[-1].content[0].text result_file_id = result.annotations[0].file_path.file_id result_file_name = pathlib.Path(result.annotations[0].text).name with open(result_file_name, "wb") as f: f.write(client.files.content(result_file_id).read())
今回ダウンロードされたファイルは以下です。
payment_method,amount bank_transfer,41100 coupon,18500 credit_card,87100 gift_card,20500
置き換えるべきテキストはannotationsにstart_index、end_indexがあるため、そちらを参照してユーザに公開するリンクに置き換えます。
display_message = result.value[:result.annotations[0].start_index] \ + "ユーザに公開するリンク" \ + result.value[result.annotations[0].end_index:] print(display_message) # 各支払い方法ごとの金額の総和を計算し、その結果をCSVファイルに保存しました。結果は以下のリンクからダウンロードできます: # # [total_amount_by_payment_method_correct.csv](ユーザに公開するリンク)
Code Interpreterのstepsを確認
前述のレスポンスは得られた結果のみとなりますので、Code Interpreterが実際にどのようなコードを実行したかまではわかりません。
それを確認するためには、stepsをみる必要があります。
以下のようにrunのstepsを確認すると、実際に実行されたコードやコードの出力が確認できます。
run_steps = client.beta.threads.runs.steps.list( thread_id=thread.id, run_id=run.id, order='asc' ) # print(run_steps.model_dump_json(indent=2)) for i in [i.step_details for i in run_steps.data]: if i.type == "tool_calls": for j in i.tool_calls: if j.type == "code_interpreter": print("="*80) print("tool_calls - code_interpreter") print("="*80) print("\nINPUT:>\n") print(j.code_interpreter.input) print("\nOUTPUT:>\n") print(j.code_interpreter.outputs) elif i.type == "message_creation": print("="*80) print("message_creation") print("="*80) message_id = i.message_creation.message_id message = client.beta.threads.messages.retrieve(message_id=message_id, thread_id=thread.id) print(message.content[0].text.value) # ================================================================================ # tool_calls - code_interpreter # ================================================================================ # # INPUT:> # # import pandas as pd # # # ファイルパスを指定 # file_path = '/mnt/data/raw_payments.csv' # # # CSVファイルを読み込む # payments = pd.read_csv(file_path) # # # 各payment_methodごとのamountの総和を求める # total_amount_by_method = payments.groupby('payment_method')['amount'].sum().reset_index() # # # ファイル名を指定してCSVに保存 # output_file_path = '/mnt/data/total_amount_by_payment_method.csv' # total_amount_by_method.to_csv(output_file_path, index=False) # # output_file_path # # OUTPUT:> # # [CodeInterpreterOutputLogs(logs='---------------------------------------------------------------------------\nFileNotFoundError Traceback (most recent call last)\nCell In[1], line 7\n 4 file_path = \'/mnt/data/raw_payments.csv\'\n 6 # CSVファイルを読み込む\n----> 7 payments = pd.read_csv(file_path)\n 9 # 各payment_methodごとのamountの総和を求める\n 10 total_amount_by_method = payments.groupby(\'payment_method\')[\'amount\'].sum().reset_index()\n\nFile ~/.local/lib/python3.8/site-packages/pandas/util/_decorators.py:311, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)\n 305 if len(args) > num_allow_args:\n 306 warnings.warn(\n 307 msg.format(arguments=arguments),\n 308 FutureWarning,\n 309 stacklevel=stacklevel,\n 310 )\n--> 311 return func(*args, **kwargs)\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/readers.py:586, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, error_bad_lines, warn_bad_lines, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options)\n 571 kwds_defaults = _refine_defaults_read(\n 572 dialect,\n 573 delimiter,\n (...)\n 582 defaults={"delimiter": ","},\n 583 )\n 584 kwds.update(kwds_defaults)\n--> 586 return _read(filepath_or_buffer, kwds)\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/readers.py:482, in _read(filepath_or_buffer, kwds)\n 479 _validate_names(kwds.get("names", None))\n 481 # Create the parser.\n--> 482 parser = TextFileReader(filepath_or_buffer, **kwds)\n 484 if chunksize or iterator:\n 485 return parser\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/readers.py:811, in TextFileReader.__init__(self, f, engine, **kwds)\n 808 if "has_index_names" in kwds:\n 809 self.options["has_index_names"] = kwds["has_index_names"]\n--> 811 self._engine = self._make_engine(self.engine)\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1040, in TextFileReader._make_engine(self, engine)\n 1036 raise ValueError(\n 1037 f"Unknown engine: {engine} (valid options are {mapping.keys()})"\n 1038 )\n 1039 # error: Too many arguments for "ParserBase"\n-> 1040 return mapping[engine](self.f, **self.options)\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/c_parser_wrapper.py:51, in CParserWrapper.__init__(self, src, **kwds)\n 48 kwds["usecols"] = self.usecols\n 50 # open handles\n---> 51 self._open_handles(src, kwds)\n 52 assert self.handles is not None\n 54 # Have to pass int, would break tests using TextReader directly otherwise :(\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/parsers/base_parser.py:222, in ParserBase._open_handles(self, src, kwds)\n 218 def _open_handles(self, src: FilePathOrBuffer, kwds: dict[str, Any]) -> None:\n 219 """\n 220 Let the readers open IOHandles after they are done with their potential raises.\n 221 """\n--> 222 self.handles = get_handle(\n 223 src,\n 224 "r",\n 225 encoding=kwds.get("encoding", None),\n 226 compression=kwds.get("compression", None),\n 227 memory_map=kwds.get("memory_map", False),\n 228 storage_options=kwds.get("storage_options", None),\n 229 errors=kwds.get("encoding_errors", "strict"),\n 230 )\n\nFile ~/.local/lib/python3.8/site-packages/pandas/io/common.py:701, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\n 696 elif isinstance(handle, str):\n 697 # Check whether the filename is to be opened in binary mode.\n 698 # Binary mode does not support \'encoding\' and \'newline\'.\n 699 if ioargs.encoding and "b" not in ioargs.mode:\n 700 # Encoding\n--> 701 handle = open(\n 702 handle,\n 703 ioargs.mode,\n 704 encoding=ioargs.encoding,\n 705 errors=errors,\n 706 newline="",\n 707 )\n 708 else:\n 709 # Binary mode\n 710 handle = open(handle, ioargs.mode)\n\nFileNotFoundError: [Errno 2] No such file or directory: \'/mnt/data/raw_payments.csv\'\n', type='logs')] # ================================================================================ # message_creation # ================================================================================ # ファイル`raw_payments.csv`が存在しないため、エラーが発生しています。アップロードされたファイルを確認して、該当するファイルを処理するようにします。アップロードされたファイル名を確認し、それに応じて処理を行います。 # ================================================================================ # tool_calls - code_interpreter # ================================================================================ # # INPUT:> # # # アップロードされたファイル名のリストを作成 # uploaded_files = [ # '/mnt/data/file-NjPcqnSI1rcFIrGkMz83DoNb', # '/mnt/data/file-nYt31owJ3APz6jaTNmRJ0gRG', # '/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se' # ] # # # アップロードされたファイル名を確認 # uploaded_files # # OUTPUT:> # # [CodeInterpreterOutputLogs(logs="['/mnt/data/file-NjPcqnSI1rcFIrGkMz83DoNb',\n '/mnt/data/file-nYt31owJ3APz6jaTNmRJ0gRG',\n '/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se']", type='logs')] # ================================================================================ # message_creation # ================================================================================ # アップロードされたファイルは以下の三つですが、正しいファイル名が指定されていませんでした。 # # - `/mnt/data/file-NjPcqnSI1rcFIrGkMz83DoNb` # - `/mnt/data/file-nYt31owJ3APz6jaTNmRJ0gRG` # - `/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se` # # これらのファイルの中で、`raw_payments.csv`に相当するものを探し、該当する操作を行います。まず、これらのファイルの内容を確認します。 # ================================================================================ # tool_calls - code_interpreter # ================================================================================ # # INPUT:> # # # アップロードされたファイルの内容を確認(先頭の数行を表示) # for file_path in uploaded_files: # print(f"Contents of {file_path}:") # try: # df = pd.read_csv(file_path) # print(df.head(), '\n') # except Exception as e: # print(f"Error reading {file_path}: {e}\n") # # OUTPUT:> # # [CodeInterpreterOutputLogs(logs='Contents of /mnt/data/file-NjPcqnSI1rcFIrGkMz83DoNb:\n id first_name last_name\n0 1 Michael P.\n1 2 Shawn M.\n2 3 Kathleen P.\n3 4 Jimmy C.\n4 5 Katherine R. \n\nContents of /mnt/data/file-nYt31owJ3APz6jaTNmRJ0gRG:\n id user_id order_date status\n0 1 1 2018-01-01 returned\n1 2 3 2018-01-02 completed\n2 3 94 2018-01-04 completed\n3 4 50 2018-01-05 completed\n4 5 64 2018-01-05 completed \n\nContents of /mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se:\n id order_id payment_method amount\n0 1 1 credit_card 1000\n1 2 2 credit_card 2000\n2 3 3 coupon 100\n3 4 4 coupon 2500\n4 5 5 bank_transfer 1700 \n\n', type='logs')] # ================================================================================ # message_creation # ================================================================================ # `raw_payments.csv`に相当するファイルは `/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se` です。このファイルには、支払い方法 (`payment_method`) ごとに、金額 (`amount`) が記載されています。 # # このファイルを用いて各支払い方法ごとの金額の総和を計算し、結果を新たなCSVファイルに保存します。 # ================================================================================ # tool_calls - code_interpreter # ================================================================================ # # INPUT:> # # # 正しいファイルパスを指定してデータをロード # correct_file_path = '/mnt/data/file-qdS80m8mXAy8xnzV9CqlJ7se' # payments_correct = pd.read_csv(correct_file_path) # # # 各payment_methodごとのamountの総和を計算 # total_amount_by_method_correct = payments_correct.groupby('payment_method')['amount'].sum().reset_index() # # # 結果をCSVファイルに保存 # output_correct_file_path = '/mnt/data/total_amount_by_payment_method_correct.csv' # total_amount_by_method_correct.to_csv(output_correct_file_path, index=False) # # output_correct_file_path # # OUTPUT:> # # [CodeInterpreterOutputLogs(logs="'/mnt/data/total_amount_by_payment_method_correct.csv'", type='logs')] # ================================================================================ # message_creation # ================================================================================ # 各支払い方法ごとの金額の総和を計算し、その結果をCSVファイルに保存しました。結果は以下のリンクからダウンロードできます: # # [total_amount_by_payment_method_correct.csv](sandbox:/mnt/data/total_amount_by_payment_method_correct.csv)
raw_payments.csv
の読み込みに失敗したため、ファイルの先頭を確認してraw_payments.csv
が今あるファイルのいずれかなのか把握するなど、挙動を確認することができます。
ファイルが決まった後は、pandasのgroupbyを使って所望の結果を得ていることが分かります。
リソースの削除
リソースは残っていると費用が掛かるケースがありますので削除しておきましょう
resp = client.beta.threads.delete(thread_id=thread.id) print(resp) # ThreadDeleted(id='thread_naDHVrafHHDXYjfifmrlkbJc', deleted=True, object='thread.deleted')
for file in files: resp = client.files.delete(file_id=file.id) print(resp) # FileDeleted(id='file-NjPcqnSI1rcFIrGkMz83DoNb', deleted=True, object='file') # FileDeleted(id='file-nYt31owJ3APz6jaTNmRJ0gRG', deleted=True, object='file') # FileDeleted(id='file-qdS80m8mXAy8xnzV9CqlJ7se', deleted=True, object='file')
resp = client.beta.assistants.delete(assistant_id=assistant.id) print(resp) # AssistantDeleted(id='asst_H24X1ae9Pdx7Ufceqdkj5GVa', deleted=True, object='assistant.deleted')
まとめ
いかがでしたでしょうか。更にAssistants APIについての理解が深まりました。
本記事が皆様のご参考になれば幸いです。