2025年3月13日木曜日

APEXアプリケーションに入力したメッセージをDifyのアプリケーションに送信する

先日、Oracle APEXのアプリケーションにiframeで埋め込んだOpen WebUIに、APEXアプリケーションからメッセージを送信できるようにしました。今回はOpen WebUIの代わりにDifyのアプリケーションにメッセージを送ってみます。

APEXアプリケーションは以下のように動作します。


リーバス・プロキシの構成はOpen WebUIの記事と同じです。Difyは以下の記事に従って、ローカルのコンテナ環境で実行します。ただし、EXPOSE_NGINX_PORT3000を設定し、Open WebUIと同じリバース・プロキシの設定で動作するようにします。

# ------------------------------ 

# Docker Compose Service Expose Host Port Configurations

# ------------------------------

EXPOSE_NGINX_PORT=3000

EXPOSE_NGINX_SSL_PORT=3443


参照する記事:Oracle Database 23ai Freeをベクトル・ストアとしたDifyのローカル環境を作成する

Difyで簡単なチャットボットのアプリケーションを作成し、公開します。


サイトに埋め込むを開きます。

埋め込み方法としてiframeを選択し、埋め込むコードをコピーします。


APEXアプリケーションの構成はOpen WebUIの記事で作成したものと同じです。

以下に違いを説明します。

Difyでは埋め込むiframeのHTMLを生成してくれているので、それを使うようにします。URLのリージョンの代わりに静的コンテンツのリージョンを作成し、ソースHTMLコードに、DifyからコピーしたHTMLを記述します。外観テンプレートは装飾の少ないBlank with Attributesを選択します。


ページ・プロパティJavaScriptファンクションおよびグローバル変数の宣言に、以下を記述します。Difyのテキスト入力領域はReactコンポーネントのようで、テキストの更新に特別な処理が必要になっています。

Claude 3.7 Sonnetに教えてもらいました。
const channel = new BroadcastChannel('submit-message');

/*
* Reactコンポーネント内のtextareaへの入力シミュレーション
*
* Claude 3.7 Sonnetが以下のプロンプトで教えてくれたコード。
*
* 「textarea要素へのキーボード入力をJavaScriptでシミュレートするには?」
* 「Reactのコンポーネントのキーボード入力をシミュレートするには、どのような内部的な処理が必要ですか?」
*/
function simulateReactTextAreaInput(textareaElement, text) {
    // 1. 値の変更
    // Reactのstate更新をトリガーするためには、changeイベントが必要
    const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
        window.HTMLTextAreaElement.prototype, 'value'
    ).set;
    nativeInputValueSetter.call(textareaElement, text);
  
    // 2. Reactの合成イベントをディスパッチ
    const reactChangeEvent = new Event('input', { bubbles: true });
    textareaElement.dispatchEvent(reactChangeEvent);
  
    // Reactのonchangeハンドラをトリガーするためのイベント
    const reactInputEvent = new Event('change', { bubbles: true });
    textareaElement.dispatchEvent(reactInputEvent);
}
ページ・ロード時に実行に以下を記述します。
channel.addEventListener("message", (event) => {
    const text = event.data.message;
    // iframe内のtextareaを取得する。
    const iframe = document.querySelector('iframe');
    const doc = iframe.contentWindow.document;
    const textarea = doc.querySelector("textarea");
    console.log(textarea);
    // Reactコンポーネントへのテキスト入力。
    simulateReactTextAreaInput(textarea, text);
    // 送信ボタンのクリック。
    setTimeout(() => {
        const parent = textarea.parentElement.parentElement;
        const button = parent.querySelector('button');
        console.log(button);
        button.click();
    }, 1000);
});
以上で、Dify向けのメッセージの受信側の実装は完了です。アプリケーションを実行すると、記事の先頭のGIF動画のように操作できます。

今回の記事は以上になります。

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