ラベル Ajaxコールバック の投稿を表示しています。 すべての投稿を表示
ラベル Ajaxコールバック の投稿を表示しています。 すべての投稿を表示

2025年8月28日木曜日

LLMに写真の説明してもらうアプリをページ送信の代わりに動的アクションで実装する

以前に記事「マルチモーダルLLMのGemma3をLM Studioで動かしAPEXアプリケーションから呼び出す」で、LM Studioで動かしているGemma3に写真の説明をしてもらうアプリケーションを作成しました。ブラウザで選択した写真をデータベース・サーバーに送信するために、ページの送信を行なっています。

世界ではAPEX Developer Blogsというサイトが運用されていて、このサイトに自分の技術ブログを登録していると、新着記事が自動的に一覧に表示されます。

新着記事を見ていて、Arun Mohanさんの以下の記事が目に止まりました。

How to Handle Large Data in APEX AJAX Calls (Bypassing the 32K Limit)?

Ajaxコールバックで32kを超えるデータを受け取る方法が紹介されています。

APEXのいつのバージョンからか分かりませんが、p_clob_01というパラメータが追加されているようです。これを使うことにより、簡単に32kを超えるデータをCLOBとしてAjaxコールバックに渡すことができるようになっています。

この機能を使って、先の記事のアプリケーションを作り直してみました。作り直したアプリケーションは以下のように動作します。

選択したファイルを変更したイベントを受けて、動的アクションを実行しています。動的アクションでプレビューの表示およびAjaxコールバックを介したLLMの呼び出しを行い、結果をページ・アイテムに設定しています。

ページの送信は行なっていません。


作成したAPEXアプリケーションを簡単に説明します。機能はすべてホーム・ページに実装しています。

写真を選択するページ・アイテムをP1_IMAGEとして作成しています。このページ・アイテムでファイルを選択したときに、以下のJavaScriptを実行します。

選択した写真のプレビューを行った後に、写真のデータを属性p_clob_01としてAjaxコールバックEXPLAIN_IMAGEに与え、プロンプト(ページ・アイテムP1_PROMPT)と共に送信しています。EXPLAIN_IMAGEのレスポンスはLLMが返すレスポンスをそのまま返しているため、フロントエンドでdata.choices[0].message.contentとして答えの文章を取り出しています。



AjaxコールバックEXPLAIN_IMAGEとして、以下のPL/SQLコードを記述しています。

送信された写真(p_clob01として渡されたデータ)は、AjaxコールバックからはAPEX_APPLICATION.G_CLOB_01として参照できます。後はLM Studioで動作しているモデルgemma-3n-e4b-it-mlx@?を素直に呼び出しています。



今回の記事で作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/explain-image-by-dynamic-action-and-ajax-callback.zip

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

2023年7月6日木曜日

対話グリッドの選択リストの列に動的アクションで値を設定する

 対話グリッドの列に設定した値より、別の列の選択リストに値を設定する方法を紹介します。

以下の動画のように、列Product Name製品名を入力したときに、列Shop販売会社を設定します。列Shopに設定された販売会社は初期値で、選択リストを開いて変更できます。


以下のスクリプトを実行し、上記のサンプル・アプリケーションで使用するスキーマを作成します。


アプリケーション作成ウィザードを起動します。アプリケーションの名前選択リストの初期化とします。

ホーム・ページを削除し、代わりに対話グリッドのページを追加します。


対話グリッドのページは、以下の設定で作成します。

ページ名Orders表またはビュー編集を許可を選択します。

表またはビューとしてSHP_ORDERSを選択します。

詳細ホームページとして設定にチェックを入れます。


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

アプリケーションが作成されたら、ページ・デザイナで対話グリッドのページを開きます。

ページ・プロパティJavaScriptファンクションおよびグローバル変数の宣言に以下を記述します。

var defaultShops;

この変数defaultShopsは、製品名と販売会社の組み合わせをキャッシュするために使用します。


対話グリッドShp Ordersを選択し、静的IDとしてordersを設定します。


プロセス・ビューを開きます。

製品名より販売会社の初期値を求めるプロセスを、Ajaxコールバックとして作成します。

識別名前GET_DEFAULT_SHOPとします。この名前は、JavaScript側から呼び出すファンクションapex.server.processの引数として与えるため、変更はできません(変更する場合は、apex.server.processの引数も変更する)。

タイプコードを実行を選び、ソースPL/SQLコードとして以下を記述します。



レンダリング・ビューを開きます。

PRODUCT_NAME動的アクションを作成します。

識別名前onChange ProductNameタイミングはデフォルトでイベント変更選択タイプ対話グリッドShp OrdersPRODUCT_NAMEになります。


TRUEアクションとしてJavaScriptコードの実行を選択し、設定コードとして以下を記述します。

ページ・アイテムのAPIのsetValueは、引数として表示値(pDisplayValue)、値(pValue)を指定できますが、対話グリッドのsetValueは値(pValue)のみです。そのため、対話グリッドの選択リストやポップアップLOVへ値を設定するには、JSON形式{ d: "表示値", v: "値" } で渡します。


この状態でアプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

とはいえ、対話グリッドに製品名を入力するたびに、ブラウザからデータベースへの問合せが発生するため、今ひとつ反応が良くありません。

ページが開いた時点で、製品名と販売会社の組み合わせを変数defaultShopsにキャッシュする機能を追加します。

プロセス・ビューを開き、AjaxコールバックとしてGET_DEFAULT_SHOPSを作成します。PL/SQLコードとして以下を記述します。



レンダリング・ビューに戻り、ページ・プロパティJavaScriptページ・ロード時に実行に以下を記述します。



以上でアプリケーションは完成です。

今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/ig-set-selectlist-default.zip

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

2023年5月18日木曜日

対話モード・レポートの列を動的アクションで更新する

対話モード・レポートの列にチェックボックスを配置し、その値をページを送信せずに更新するにはどうしたら?という相談がありました。APEX_ITEM.CHECKBOX2の使用を考えていて、その場合、ページを送信する必要があります。

ページを送信せずにデータベースに保存されているデータを更新するには、動的アクションを使えます。下のレイヤーで考えると、ページの送信はHTTPのPOSTリクエストの発行による更新、動的アクションはAjaxコールの発行による更新です。

ただし、動的アクションによる更新の場合、失われた更新の防止(Lost Write Protection)が行われません。

単に動的アクションで更新するだけであれば、それほど実装は難しくありません。ロスト・ライト・プロテクションについても実装してみようと思います。

以下の動作するアプリケーションを作成します。上の画面でチェックボックスをチェックしたり外したりします。すでに上の画面でデータを変更しているため、下の画面で同じ行のチェックボックスを操作しようとするとエラーが発生します。

エラーが発生したら、一旦、ページをリロードします。ページをリロードすると直前のデータベースの状態がレポートに反映されるため、チェックボックスの値を変更できます。下の画面でデータを更新すると、今度は上の画面でチェックボックスを操作しようするとエラーが発生します。


アプリケーションで使用する表CBX_STATEMENTSを作成します。

クイックSQLの以下のモデルを使用します。
# prefix: cbx
# rowversion: true
# auditcols: true
statements
    message     vc80 /nn
    is_approved vc1  /nn /check Y,N /default N
ロスト・ライト・プロテクションの実装に、行バージョンを使用します。そのためクイックSQLのモデルにrowversion: trueを指定します。行バージョンの代わりにチェックサムを使うこともできますが、異なる実装になります。(APEXはロスト・ライト・プロテクションにチェックサムを使っています)保護対象をすべての列ではなく、一部の列に限定する場合はチェックサムによる実装が必要です。

クイックSQLでは表CBX_STATEMENTSの作成までを行い、アプリケーションの作成はしません。


表が作成されたら、アプリケーション作成ウィザードを起動します。

アプリケーションの名前Checkbox on IRとします。デフォルトで作成されているホーム・ページを削除し、代わりに対話モード・レポートのページIR対話グリッドのページIGを追加します。


対話モード・レポートのページ定義です。表またはビューとしてCBX_STATEMENTSを指定します。動的アクションによるデータの更新は、このページに実装します。


対話グリッドのページ定義です。対話グリッドは表CBX_STATEMENTSにデータを投入するために使用します。


以上でアプリケーションを作成します。

アプリケーションが作成されたら、ページ番号のIRのページを開きます。

最初に対話モード・レポートのリージョンに静的IDを設定します。詳細静的IDstatementsと記述します。


IS_APPROVEDには、データが文字のまま(YまたはN)表示されるようになっています。チェックボックスとして表示されるよう、以下のコードを列の書式HTML式に記述します。チェックボックスの値が変更されるたびに、列IDROW_VERSIONチェックボックスのステータスを含んだINPUT要素に紐づけた(CSSクラスdummychangeで紐づける)動的アクションが呼び出されます。



動的アクション・ビューを開き、動的アクションを作成します。

識別名前チェックボックスの値変更とします。

実行イベント有効範囲動的とし、静的コンテナ(jQueryセレクタ)には#statementsを指定します。これは対話モード・レポートのリージョンです。タイプ即時です。

タイミングイベント変更選択タイプとしてjQueryセレクタを選択します。jQueryセレクタとして.dummychangeを指定し、列IS_APPROVEDHTML式に記述したINPUT要素を指定します。


TRUEアクションとしてJavaScriptコードの実行を選択し、設定コードに以下を記述します。Ajaxコールバックとして実装したUPDATE_CHECKBOXを呼び出します。引数x01に列IDx02に列ROW_VERSIONx03チェックボックスのステータスを渡し、Ajaxコールバックとして実装したプロセスUPDATE_CHECKBOXを呼び出します。



プロセス・ビューを開き、AjaxコールバックとしてプロセスUPDATE_CHECKBOXを作成します。ソースPL/SQLコードとして以下を記述します。



以上でアプリケーションは完成です。

アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/checkbox-on-ir.zip

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