以前にOpenAIのChat Completions APIが使えるようになった頃に、同じテーマで記事を書いています。それから時間も経ち、OllamaやLlama.cppといったOpenAIのChat Completions API互換のAPIをサポートするソフトウェアも利用できるようになりました。Chat Completions API自体には互換性があるため、これらを同様に扱えるひとつのAPEXアプリを作ってみることにしました。
とにかくChat Completions APIを呼び出せれば良いので、ユーザー・インターフェースの作り込みは最小限にします。APIの呼び出しはPL/SQLのパッケージUTL_OPENAI_CHAT_APIにまとめて実装しています。パッケージのコードは記事の末尾に添付します。パッケージUTL_OPENAI_CHAT_APIはツール呼び出しに関する実装も含んでいます。
作成したアプリケーションは以下のように動作します。
以下よりAPEXアプリケーションの作成手順を紹介します。
今回はChat Completions APIを呼び出す対象をOpenAI、モデルは廉価なgpt-3.5-turboを使います。そのため、OpenAIのAPIキーをAPEXのWeb資格証明として作成しておきます。
ワークスペース・ユーティリティのWeb資格証明を作成します。
Web資格証明の名前はOpenAI API Keyとしています。使用するWeb資格証明の指定には静的識別子を使用するため、この名前はなんでもかまいません。
静的識別子としてOPENAI_API_KEY、認証タイプはHTTPヘッダー、資格証明名はAuthorizationとします。資格証明シークレットしてBearerで始めて空白で区切った後、OpenAIのAPIキーを続けた文字列を設定します。
アプリケーション・ビルダーからアプリケーションの作成を呼び出し、空のアプリケーションを作成します。
名前はChat with Generative AIとします。
アプリケーションの作成をクリックします。
空のアプリケーションが作成されます。Chat Completions APIを呼び出す機能はすべてホーム・ページに実装します。
最初に置換文字列に各種パラメータを設定します。アプリケーション定義の編集を開きます。
アプリケーション定義の置換のセクションを開きます。
置換文字列として呼び出すサービスとモデルの指定に必要な情報を設定します。
呼び出す対象はOpenAIなので、G_API_ENDPOINTとしてhttps://api.openai.com/v1/chat/completionsを設定します。G_CHAT_HISTORYにはチャット履歴を保存するAPEXコレクションの名前としてCHAT_HISTORYを設定します。これはアプリケーション内で同じ名前のコレクションを参照させるためのもので、どのような名前でも構いませんが、あえて変更する必要もないでしょう。G_MODEL_NAMEはgpt-3.5-turboを指定します。G_CREDENTIALとしてOpenAIのAPIキーを登録したWeb資格証明であるOPENAI_API_KEYを設定します。
以上を設定して、変更の適用をクリックします。
ページ・デザイナでホーム・ページを開きます。
最初にチャット履歴を初期化するボタンを作成します。ボタンはブレッドクラムのリージョンChat with Generative AIに作成します。
識別のボタン名はINIT、ラベルはStart New Conversationとします。レイアウトの位置にNextを選択します。
動作のアクションとしてこのアプリケーションのページにリダイレクトを選択します。
ターゲットをクリックしリンク・ビルダーを開きます。
ターゲットのページに&APP_PAGE_ID.を記述します。これはこのボタンがあるページ番号、つまり自ページの呼び出しを指定しています。詳細のリクエストにINIT_CONVERSATIONを設定します。
OKをクリックし、リンク・ビルダーを閉じます。
このボタンを押した時に実行されるプロセスを作成します。
レンダリング前のヘッダーの前にプロセスを作成します。
識別の名前はInit Conversationとします。タイプはコードの実行です。ソースのPL/SQLコードとして以下を記述します。APEXコレクションが作成されていないか(サインイン直後)、またはREQUESTにINIT_CONVERSATIONが設定されている場合(ボタンStart New Conversationが押されたとき)に、APEXコレクションを初期化します。最初にロールがsystemの空のプロンプトを挿入します。このsystemプロンプトは変更できるように、画面にUIを実装します。
新規にリージョンを作成します。
識別のタイトルはSystem Promptとします。タイプは静的コンテンツです。
作成したリージョンに、プロンプトを入力するページ・アイテムを作成します。
識別の名前はP1_PROMPT、タイプはテキスト領域とします。ラベルはPromptです。セッション・ステートのデータ型はCLOB、ストレージにセッションごと(永続)を選択します。
入力したsystemプロンプトをチャット履歴に設定するボタンを作成します。
識別のボタン名はSET_PROMPT、ラベルはSet Promptとします。動作のアクションはデフォルトのページの送信です。
ボタンSET_PROMPTをクリックしたときに実行するプロセスを作成します。
左ペインでプロセス・ビューを開き、新規にプロセスを作成します。
識別の名前はSet Promptとします。タイプはコードを実行です。ソースのPL/SQLコードとして以下を記述します。すでに登録済みのsystemプロンプトを置き換えます。
サーバー側の条件のボタン押下時にSET_PROMPTを指定します。
ユーザーによるメッセージを送信するUIを作成します。
新規にリージョンを作成します。
識別のタイトルはUser Messageとします。タイプは静的コンテンツです。
作成したリージョンに、ユーザーによるメッセージを入力するページ・アイテムを作成します。
識別の名前はP1_MESSAGE、タイプはテキスト領域とします。ラベルはMessageです。セッション・ステートのデータ型はCLOB、ストレージにリクエストごと(メモリーのみ)を選択します。
入力したメッセージを含めて、Chat Completions APIを呼び出すボタンを作成します。
識別のボタン名はSEND_MESSAGE、ラベルはSend Messageとします。動作のアクションはデフォルトのページの送信です。
Chat Completions APIのレスポンスを含めた、チャット履歴を表示するリージョンを作成します。
識別のタイトルはChat History、タイプはカードを選びます。ソースのタイプにSQL問合せを選択し、SQL問合せとして以下を記述します。
select seq_id, c001, c002, clob001, n001, n002, n003
from apex_collections
where collection_name = :G_CHAT_HISTORY order by seq_id desc
カードに表示する内容を設定します。プロパティ・エディタの属性タブを開きます。
外観のレイアウトとして水平(行)を選びます。カードの主キー列1はSEQ_IDです。
タイトルの列はC001、サブタイトルの列はC002、本体の列はCLOB001を選択します。2次本体の拡張フォーマットをオンにし、HTML式として以下を記述します。
{if N001/}
prompt_tokens: &N001. completion_tokens: &N002. total_tokens: &N003.
{endif/}
デバッグ用にChat Completions APIに送信したリクエストと、受信したレスポンスを表示するページ・アイテムを作成します。
送信したリクエストを保持するページ・アイテムはP1_REQUESTとして作成します。ラベルはRequest、設定のページの送信時に送信はオフにします。セッション・ステートのデータ型はCLOB、ストレージはセッションごと(永続)を選択します。
同様にレスポンスを保持するページ・アイテムP1_RESPONSEを作成します。ラベルはResponseとします。
左ペインでプロセス・ビューを開き、ボタンSEND_MESSAGEをクリックしたときに実行されるプロセスを作成します。
識別の名前はSend Message、タイプはAPIの呼出しとします。設定のパッケージにUTL_OPENAI_CHAT_API、プロシージャまたはファンクションにCHATを選択します。
サーバー側の条件のボタン押下時にSEND_MESSAGEを指定します。
パラメータp_contentの値のタイプはアイテム、アイテムはP1_MESSAGEとします。
パラメータp_collection_nameの値のタイプは静的値、静的値は&G_CHAT_HISTORY.とします。
パラメータp_api_endpointの値のタイプは静的値、静的値は&G_API_ENDPOINT.とします。
パラメータp_credential_static_idの値のタイプは静的値、静的値は&G_CREDENTIAL.とします。
パラメータp_request_outの値のアイテムにP1_REQUESTを指定します。
パラメータp_response_outの値のアイテムにP1_RESPONSEを指定します。
その他のパラメータはAPIデフォルトのまま変更しません。
以上でOpenAIのChat Completions APIを呼び出すAPEXアプリは完成です。アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/chat-with-generative-ai-0.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完
コードにはツール呼び出しの対応が含まれていて、ツールに関する定義を保存する表OPENAI_TOOLSへの参照があります。そのため、以下のDDLを実行して表をあらかじめ作成しておく必要があります。