2023年11月10日金曜日

Oracle APEXのアプリケーションからOpenAIのAssistants APIを呼び出す

OpenAIよりAssistants APIのベータ版がリリースされました。Oracle APEXよりAssistants APIを呼び出すアプリケーションを作成してみました。

2023年12月1日追記

OpenAIのAssistants APIよりList threadsが削除されたようです。そのためThreadsの扱いは変更する必要があります。

以下の動画は、Assistants APIのOverviewで紹介されている手順を実行しています。


Assistants APIを呼び出すPL/SQLのパッケージをUTL_OPENAI_ASSISTANTS_APIとして作成しています。パッケージのコードは、本記事の最後に添付しています。

Assistants APIでは、オブジェクトのタイプとしてassistantassistant.filethreadmessagemessage.filerunrun.stepを定義し、それぞれのオブジェクトにCreateModifyRetrieveDeleteList(厳密にいうとListはオブジェクトへの操作ではありません)の操作を実装しています。オブジェクトのタイプによっては、一部の操作は実装されていません。例えば、messageオブジェクトにDelete操作はありません。これ以外の特別なAPIとしては、Submit tool outputs to runCreate thread and runCancel a runがあります。パッケージUTL_OPENAI_ASSISTANTS_APIにはCreate thread and runの呼び出しは含まれていません。また、List操作はRESTデータ・ソースとして作成したので、パッケージにList操作を呼び出すファンクションは含まれていません。

オブジェクト・タイプが定義されていて、それぞれのオブジェクトにいわゆるCRUD操作(Create、Read、Update、Delete)があるので、Oracle APEXとしては扱いやすい形式です。ただし、RESTサービスからはAPEXアプリケーションを自動生成することはできません。

OpenAIのAssistants APIのリファレンスには、ぞれぞれのオブジェクト・タイプの定義が記載されています。その情報を元に、仮のスキーマを生成します。クイックSQLの以下のモデルからスキーマを生成します。


SQLの生成SQLスクリプトの保存レビューおよび実行を行います。SQLの実行を確認する画面では、即時実行をクリックします。


SQLスクリプトが実行され、表や索引がすべて生成された時点で、アプリケーションの作成を実行します。


アプリケーション作成ウィザードが起動します。AssistantsThreadsMessagesといったすべてのオブジェクト・タイプに対応したフォーム付き対話モード・レポートのページが追加されています。

アプリケーションの作成を実行します。


アプリケーションが作成されます。このアプリケーションを元に、データ・ソースやプロセスをAssistants APIを呼び出すように、置き換えていきます。


アプリケーション作成直後の状態です。


Assistantsを開くと、Assistantsを一覧する対話モード・レポートのページが表示されます。

作成をクリックします。


オブジェクトAssistantsが持つ属性の入力画面が、画面右よりドロワーとして開きます。


ページ・デザイナを開きます。

フォームが開く時に、データ・ソースより値を取り出しページ・アイテムに設定するプロセス初期化フォームAssistantが作成されています。

このプロセスをAssistants APIのRetrieve assistant APIの呼び出しに置き換えます。

識別名前Retrieve assistantタイプとしてAPIの呼び出しを選択します。設定タイプPL/SQL Packageを選択し、パッケージとしてUTL_OPENAI_ASSISTANTS_APIを設定します。プロシージャまたはファンクション名RETRIEVE_ASSISTANTです。

サーバー側の条件タイプアイテムはNULLではないを選択し、アイテムとしてP3_IDを選択します。


パッケージUTL_OPENAI_ASSISTANTS_APIに実装したファンクションは、ファンクションの結果としてID値を返すようにしています。この値は、パラメータにP3_ASSISTANT_IDとして含まれています。そのため、出力を無視します。


オブジェクトAssistantの主キーとなる属性はassistant_idですが、仮に作成した表では主キーとなる列はすべてIDになっています。そのため、主キーに対応するパラメータ(Assistantではp_assistant_id)に、手動で主キーとなるページ・アイテム(今回の例ではP3_ID)を割り当てます。


また、デバッグ用に出力パラメータとしてp_responseを定義しています。APEXのプロセスから呼び出す際は、出力を無視します。


以上でフォームにデータを読み込むプロセスの置き換えができました。


左ペインでプロセス・ビューを開き、データの挿入、更新、削除を行なうプロセスを置き換えます。

最初にプロセスを削除します。


ボタンCREATEをクリックしたときに実行するプロセスを作成します。呼び出されるファンクションCREATE_ASSISTANTです。


CREATEの場合は、ファンクションの結果が主キーの値なので、値のアイテムにP3_IDを割り当てます。


デバッグ用のパラメータp_response出力は無視します。


同様の手順で、プロセスModify assistantおよびDelete assistantを作成すると、オブジェクトAssistantの操作の実装は完了です。


Assistantの一覧を取得するRESTデータ・ソースを作成します。1つ以上のAssistantを作成した後に作業を行います。データがないとデータ・プロファイルは自動的に生成されません。

共有コンポーネントRESTデータ・ソースを開きます。


作成をクリックします。


RESTデータ・ソースの作成最初からを選びます。

に進みます。


RESTデータ・ソース・タイプとして簡易HTTPを選択します。名前List assistantsとします。

URLエンドポイントはOpenAIのAPI Referenceより、以下を指定します。

https://api.openai.com/v1/assistants


List messagesのようにパスに変数が含まれる場合は、以下のように{thread_id}といった記述を:thread_idに置き換えます。

https://api.openai.com/v1/threads/{thread_id}/messages

以下に置き換えて設定します。

https://api.openai.com/v1/threads/:thread_id/messages

このようにURLに含まれるコロンで始まる名前は、URLパラメータとして認識されます。データ・プロファイルを自動生成するために、1行はデータが返される値を設定します。


リモート・サーバーサービスURLパスの設定を確認し、へ進みます。


Assistants APIのページングの仕様が不明だったため、ページ区切りタイプとしてページ区切りなしを選択しています。

へ進みます。


認証が必要ですオンにして、OpenAIのAPIを呼び出すために使用するWeb資格証明を設定します。

Assistants APIを呼び出すためには、特別なHTTPヘッダーを設定する必要があります。そのため、ここでは検出を実行できません。RESTソースの手動作成をクリックします。


RESTデータ・ソースが作成されます。編集画面を開きます。


パラメータのセクションより、パラメータの作成をクリックします。


パラメータタイプとしてHTTPヘッダーを選択し、名前OpenAI-Betaを指定します。デフォルト値assistants=v1です。静的オンにします。これでREST API呼び出し時にHTTPヘッダーとして以下が追加されます。

OpenAI-Beta: assistants=v1


同様にHTTPヘッダーとしてContent-Type: application/jsonも追加します。


必要なHTTPヘッダーが追加され、OpenAIのAssistants APIを呼び出せるようになりました。


データ・プロファイルの編集をクリックします。


Assistants APIのList操作の行セレクタdataになります。行セレクタdataを指定し、データ・プロファイルの再検出をクリックします。


List操作で返されるレスポンスにデータが含まれていれば、データ・プロファイルとして含まれる属性(列)が自動的に生成されます。

データ・プロファイルの置換をクリックします。


以上でRESTデータ・ソースの作成は完了です。変更の適用をクリックし、RESTデータ・ソースの編集画面を閉じます。


RESTデータ・ソースが作成されたら、対応する対話モード・レポートのソース位置RESTソースに変更し、RESTソースを作成したRESTデータ・ソースに変更します。


データ・ソースの設定を変更すると、対話モード・レポートにOpenAI側に作成されているオブジェクトが一覧されます。


以上が基本的な実装手順です。

オブジェクトMessageの場合のように、List messages APIで一覧を取得する際にthread_idが必要な場合は、レポートのページにページ・アイテム(この例ではP8_THREAD_ID)を作成し、それをパラメータに割り当てます。


Threadを一覧するページから、Threadを選択してMessagesのページを開くように、対話モード・レポートリンクを設定します。


オブジェクトrunのように、レポートから詳細画面を開く際に主キーの値(runの場合はrun_id)だけでなく、別のIDが必要な場合があります(runの場合はthread_id)。

デフォルトでは主キーの列だけが設定されているため、アイテムの設定にページ・アイテムと値のペアを追加する必要があります。


オブジェクトのRetrieve呼び出しで取り出せる属性の数は、ほとんどの場合、CreateやModifyで設定できる属性の数より多くなっています。Retrieveで取り出せるがCreateやModifyには含まれていない属性は、読み出しのみの属性です。そのため、フォームのページ・アイテムのタイプ表示のみに変更します。


タイプ表示のみにし、設定ページの送信時に送信オフにします。


このような作業を行なって作成したAPEXアプリケーションのエクスポートを、以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/openai-assistants-sample.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。


パッケージUTL_OPENAI_ASSISTANTS_APIのコードです。長いですが、実装している処理は単純です。