2023年11月30日木曜日

APEX 23.2のQRコードとバーコードの画像生成を確認する

Oracle APEX 23.2では、QRコードとバーコードの画像を生成する機能が追加されました。QRコードについてはページ・アイテムのタイプとしてQRコードが追加され、ノーコードで画像を生成することができます。新しく追加されたAPEX_BARCODEパッケージのプロシージャを呼び出すことにより、QRコードに加えてバーコード(CODE128とEAN8)の画像も生成できます。生成する画像のフォーマットはSVGまたはPNGです。

この新機能については、Louis Moreauxさんよるブログ記事が大変参考になります。

Oracle APEX 23.2 - Mastering QR Codes and Barcodes

実際にQRコードとバーコードを生成するAPEXアプリケーションを作成してみました。エクスポートは以下に置いています。
https://github.com/ujnak/apexapps/blob/master/exports/sample-qrcode-and-barcode.zip

アプリケーションの画面は以下です。以下の機能を実装しています。


ページ・アイテムとしてQRコードを生成する


ページ・アイテムのアイテム・タイプとしてQRコードを選択した場合は、ページ・アイテムに設定された値からQRコードが生成されます。


ページ・アイテムのタイプとしてQRコードを選択すると、プロパティとしてQRコードが現れ、データ型サイズが選択できるようになります。サイズとしてデフォルトの4種類からどれかを選ぶことができます。


ページ・アイテムとして表示したQRコードを細かく調整をするには、CSSを記述します。この方法については、前出のLouis Moreauxさんのブログ記事に書かれています。

今回のサンプル・アプリケーションでは、ページ・アイテムP1_QR_Cのサイズを以下のCSSの記述により4remにしています。
#P1_QR_C {
  --a-qrcode-size: 4rem;
}
ページ・プロパティCSSインラインに記述します。



パッケージ・プロシージャを呼び出す



プロシージャAPEX_BARCODE.GET_QRCODE_SVGおよびAPEX_BARCODE.GET_QRCODE_PNGを呼び出して、QRコードを生成します。


SVGとPNGの両方とも、動的コンテンツのリージョンとして表示しています。

SVGのソースのCLOBを返すファンクション本体として以下を記述しています。

APEX_BARCODE.GET_QRCODE_SVGでは、戻り値としてSVG要素が文字列として返されるため、そのままページに出力することができます。


APEX_BARCODE.GET_QRCODE_PNGでは、戻り値としてPNG画像のバイナリ・データが返されます。ページに出力するにはBASE64でエンコードしてIMG要素に埋め込む必要があります。



呼び出すプロシージャをAPEX_BARCODE.GET_CODE128_SVGやAPEX_BARCODE.GET_CODE128_PNGに変更すると、QRコードの代わりにCODE128のバーコードが生成されます。


EAN8では8桁の数値に限定されますが、APEX_BARCODE.GET_EAN8_SVGやAPEX_BARCODE.GET_EAN8_PNGを呼び出して、バーコードを生成します。


APEX 23.2のQRコードとバーコードの画像生成の紹介は以上になります。

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

2023年11月29日水曜日

PineconeのCanopyへ問い合わせるAPEXアプリケーションを作成する

ベクトル・データベースPineconeのサービスを提供しているPinecone Systems Inc.が、RAG(Retrieval Augmented Generation)の実装を容易にするCanopyというフレームワークをオープン・ソースで提供しています。

Introducing Canopy: An easy, free, and flexible RAG framework powered by Pinecone
https://www.pinecone.io/blog/canopy-rag-framework/

CanopyはPineconeのベクトル・データベースとOpenAIのサービスを呼び出します。そのため、Canopyの実行にはPineconeのAPIキーとOpenAIのAPIキーの両方が必要です。それぞれの準備方法については、PineconeまたはOpenAIのサイトを参照してください。Pineconeについてはインデックスが1つまでは無料で利用できます。そのため、Canopyを利用するにあたって必ずしも有料アカウントにアップグレードする必要はありません。OpenAIについては、ユーザー登録時に付与される無料クレジットを使い切っている場合は、有料アカウントへのアップグレードが必要です。

Canopyの2023年11月29日時点でのバージョン(v.0.2.0)では、RAGで使用するベクトル埋め込み(embedding)を生成するために、OpenAIのEmbeddings APIを呼び出しています。次元数が1536なので、モデルおそらくはtext-embedding-ada-002でしょう。また、回答を生成するためにOpenAIのCompletions APIを呼び出しています。

Canopy自体はOpenAIのCompletions APIと互換性のあるREST APIを提供しているため、OpenAIのCompletions APIを呼び出すクライアントであれば、Canopyへの問い合わせはエンドポイントを変更するだけで動作するはずです。

CanopyはOracle CloudのAlways Freeのコンピュート・インスタンスに実装します。Canopyを呼び出すアプリケーションは、これもAlways FreeのAutonomous DatabaseのAPEXで作成します。

Oracle CloudのAlways FreeのAutonomous Databaseから外部サービスを呼び出す場合は、HTTPS(SSL)かつDNSで名前解決ができるという制限があるため、作成したコンピュート・インスタンスに付与されているパブリックIPアドレスは、DNSにホスト名とともに設定しておく必要があります。

以下より、Canopyのインストールと構成およびAPEXのアプリケーション作成について紹介します。

Always Freeのコンピュート・インスタンスは、イメージOracle Linux 9ShapeVM.Standard.E2.1 Microで作成しました。Canopy自体はPineconeやOpenAIのAPIを呼び出すだけで重い処理をするわけではないので、計算リソースはそれほど必要ないでしょう。


コンピュート・インスタンスが作成されたら、sshで接続してCanopyの実装を始めます。

Canopyのインストールに必要なPython 3.11とCanopyのSSL対応に使用するnginxをインストールします。作業はユーザーopcで行います。

sudo dnf -y install python3.11 python3.11-pip nginx

[opc@canopy-rag ~]$ sudo dnf -y install python3.11 python3.11-pip nginx

Ksplice for Oracle Linux 9 (x86_64)                     385 kB/s | 158 kB     00:00    

Oracle Linux 9 OCI Included Packages (x86_64)            24 MB/s |  59 MB     00:02    

Oracle Linux 9 BaseOS Latest (x86_64)                    14 MB/s |  17 MB     00:01    

Oracle Linux 9 Application Stream Packages (x86_64)      19 MB/s |  26 MB     00:01    

Oracle Linux 9 Addons (x86_64)                          468 kB/s | 335 kB     00:00    

Oracle Linux 9 UEK Release 7 (x86_64)                    14 MB/s |  24 MB     00:01    

Dependencies resolved.

========================================================================================

 Package                      Arch    Version                  Repository          Size

========================================================================================

Installing:

 nginx                        x86_64  1:1.20.1-14.0.1.el9_2.1  ol9_appstream       48 k

 python3.11                   x86_64  3.11.5-1.el9_3           ol9_appstream       30 k

 python3.11-pip               noarch  22.3.1-4.el9             ol9_appstream      4.3 M

Installing dependencies:

 libnsl2                      x86_64  2.0.0-1.el9              ol9_appstream       30 k

 mpdecimal                    x86_64  2.5.1-3.el9              ol9_appstream       85 k

 nginx-core                   x86_64  1:1.20.1-14.0.1.el9_2.1  ol9_appstream      587 k

 nginx-filesystem             noarch  1:1.20.1-14.0.1.el9_2.1  ol9_appstream      8.4 k

 oracle-logos-httpd           noarch  90.2-1.0.4.el9           ol9_baseos_latest   37 k

 python3.11-libs              x86_64  3.11.5-1.el9_3           ol9_appstream       12 M

 python3.11-pip-wheel         noarch  22.3.1-4.el9             ol9_appstream      1.4 M

 python3.11-setuptools-wheel  noarch  65.5.1-2.el9             ol9_appstream      712 k

Installing weak dependencies:

 python3.11-setuptools        noarch  65.5.1-2.el9             ol9_appstream      2.3 M


Transaction Summary

========================================================================================

Install  12 Packages


[中略]


Installed:

  libnsl2-2.0.0-1.el9.x86_64                                                            

  mpdecimal-2.5.1-3.el9.x86_64                                                          

  nginx-1:1.20.1-14.0.1.el9_2.1.x86_64                                                  

  nginx-core-1:1.20.1-14.0.1.el9_2.1.x86_64                                             

  nginx-filesystem-1:1.20.1-14.0.1.el9_2.1.noarch                                       

  oracle-logos-httpd-90.2-1.0.4.el9.noarch                                              

  python3.11-3.11.5-1.el9_3.x86_64                                                      

  python3.11-libs-3.11.5-1.el9_3.x86_64                                                 

  python3.11-pip-22.3.1-4.el9.noarch                                                    

  python3.11-pip-wheel-22.3.1-4.el9.noarch                                              

  python3.11-setuptools-65.5.1-2.el9.noarch                                             

  python3.11-setuptools-wheel-65.5.1-2.el9.noarch                                       


Complete!

[opc@canopy-rag ~]$ 


CanopyにAPEXから接続するにはHTTPS(SSL)が必須であるため、Nginxで一旦HTTPSの接続を受け付けて、HTTPに変換してCanopyにリクエストを転送するようにします。NginxをHTTPSで構成するために、Let's Encryptより証明書を取得します。

証明書の取得に使用するcertbotをインストールします。

sudo dnf --enablerepo=ol9_developer_EPEL -y install certbot

[opc@canopy-rag ~]$ sudo dnf --enablerepo=ol9_developer_EPEL -y install certbot

Oracle Linux 9 EPEL Packages for Development (x86_64)    23 MB/s |  47 MB     00:02    

Last metadata expiration check: 0:00:34 ago on Wed 29 Nov 2023 01:46:02 AM GMT.

Dependencies resolved.

========================================================================================

 Package                    Arch       Version             Repository              Size

========================================================================================

Installing:

 certbot                    noarch     2.6.0-1.el9         ol9_developer_EPEL      25 k

Installing dependencies:

 fontawesome-fonts          noarch     1:4.7.0-13.el9      ol9_appstream          205 k

 python3-acme               noarch     2.6.0-1.el9         ol9_developer_EPEL     268 k

 python3-certbot            noarch     2.6.0-1.el9         ol9_developer_EPEL     1.0 M

 python3-configargparse     noarch     1.7-1.el9           ol9_developer_EPEL      56 k

 python3-josepy             noarch     1.13.0-1.el9        ol9_developer_EPEL     101 k

 python3-parsedatetime      noarch     2.6-5.el9           ol9_developer_EPEL     133 k

 python3-pyrfc3339          noarch     1.1-11.el9          ol9_developer_EPEL      36 k


Transaction Summary

========================================================================================

Install  8 Packages


[中略]


Installed:

  certbot-2.6.0-1.el9.noarch                 fontawesome-fonts-1:4.7.0-13.el9.noarch   

  python3-acme-2.6.0-1.el9.noarch            python3-certbot-2.6.0-1.el9.noarch        

  python3-configargparse-1.7-1.el9.noarch    python3-josepy-1.13.0-1.el9.noarch        

  python3-parsedatetime-2.6-5.el9.noarch     python3-pyrfc3339-1.1-11.el9.noarch       


Complete!

[opc@canopy-rag ~]$ 


サービスhttphttpsおよびポート8000/tcpでの接続を許可するよう、firewalldを構成します。

sudo firewall-cmd --add-service=http
sudo firewall-cmd --add-service=https
sudo firewall-cmd --add-port=8000/tcp
sudo firewall-cmd --runtime-to-permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

[opc@canopy-rag ~]$ sudo firewall-cmd --add-service=http

success

[opc@canopy-rag ~]$ sudo firewall-cmd --add-service=https

success

[opc@canopy-rag ~]$ sudo firewall-cmd --add-port=8000/tcp

success

[opc@canopy-rag ~]$ sudo firewall-cmd --runtime-to-permanent

success

[opc@canopy-rag ~]$ sudo firewall-cmd --reload

success

[opc@canopy-rag ~]$ sudo firewall-cmd --list-all

public (active)

  target: default

  icmp-block-inversion: no

  interfaces: ens3

  sources: 

  services: dhcpv6-client http https ssh

  ports: 8000/tcp

  protocols: 

  forward: yes

  masquerade: no

  forward-ports: 

  source-ports: 

  icmp-blocks: 

  rich rules: 

[opc@canopy-rag ~]$ 


SELinuxの設定で、Nginxによるリバース・プロキシを許可します。

sudo setsebool -P httpd_can_network_connect 1

[opc@canopy-rag ~]$ sudo setsebool -P httpd_can_network_connect 1

[opc@canopy-rag ~]$ 


Canopyをインストールします。Canopyのインストール手順は、GitHubに記載されています。今回はVirutal Environmentの構成はスキップします。

pip3.11 install canopy-sdk

[opc@canopy-rag ~]$ pip3.11 install canopy-sdk

Defaulting to user installation because normal site-packages is not writeable

Collecting canopy-sdk

  Using cached canopy_sdk-0.2.0-py3-none-any.whl (72 kB)

Collecting fastapi<0.93.0,>=0.92.0

  Using cached fastapi-0.92.0-py3-none-any.whl (56 kB)

Collecting gunicorn<22.0.0,>=21.2.0

  Using cached gunicorn-21.2.0-py3-none-any.whl (80 kB)

Collecting jsonschema<5.0.0,>=4.2.0

  Using cached jsonschema-4.20.0-py3-none-any.whl (84 kB)

Collecting openai<2.0.0,>=1.2.3

  Using cached openai-1.3.6-py3-none-any.whl (220 kB)

Collecting pandas-stubs<3.0.0.0,>=2.0.3.230814

  Using cached pandas_stubs-2.1.1.230928-py3-none-any.whl (153 kB)

Collecting pinecone-client<3.0.0,>=2.2.2


[中略]


  Running setup.py install for wget ... done

Successfully installed aiobotocore-2.7.0 aiohttp-3.9.1 aioitertools-0.11.0 aiosignal-1.3.1 anyio-3.7.1 attrs-23.1.0 botocore-1.31.64 cachetools-5.3.2 canopy-sdk-0.2.0 certifi-2023.11.17 charset-normalizer-3.3.2 click-8.1.7 decorator-5.1.1 distro-1.8.0 dnspython-2.4.2 fastapi-0.92.0 frozenlist-1.4.0 fsspec-2023.10.0 gcsfs-2023.10.0 google-api-core-2.14.0 google-auth-2.23.4 google-auth-oauthlib-1.1.0 google-cloud-core-2.3.3 google-cloud-storage-2.13.0 google-crc32c-1.5.0 google-resumable-media-2.6.0 googleapis-common-protos-1.61.0 gunicorn-21.2.0 h11-0.14.0 httpcore-1.0.2 httpx-0.25.2 idna-3.6 jmespath-1.0.1 joblib-1.3.2 jsonschema-4.20.0 jsonschema-specifications-2023.11.1 loguru-0.7.2 mmh3-3.1.0 multidict-6.0.4 nltk-3.8.1 numpy-1.25.2 oauthlib-3.2.2 openai-1.3.6 packaging-23.2 pandas-2.1.3 pandas-stubs-2.0.3.230814 pinecone-client-2.2.4 pinecone-datasets-0.6.2 pinecone-text-0.7.0 prompt-toolkit-3.0.41 protobuf-4.25.1 pyarrow-11.0.0 pyasn1-0.5.1 pyasn1-modules-0.3.0 pydantic-1.10.13 python-dateutil-2.8.2 python-dotenv-1.0.0 pytz-2023.3.post1 pyyaml-6.0.1 referencing-0.31.0 regex-2023.10.3 requests-2.31.0 requests-oauthlib-1.3.1 rpds-py-0.13.1 rsa-4.9 s3fs-2023.10.0 six-1.16.0 sniffio-1.3.0 sse-starlette-1.8.2 starlette-0.25.0 tenacity-8.2.3 tiktoken-0.3.3 tqdm-4.66.1 types-jsonschema-4.20.0.0 types-pytz-2023.3.1.1 types-pyyaml-6.0.12.12 types-tqdm-4.66.0.5 typing-extensions-4.8.0 tzdata-2023.3 urllib3-2.0.7 uvicorn-0.20.0 wcwidth-0.2.12 wget-3.2 wrapt-1.16.0 yarl-1.9.3

[opc@canopy-rag ~]$ 


環境変数の設定を行います。

export PINECONE_API_KEY="<PINECONE_API_KEY>"

export PINECONE_ENVIRONMENT="<PINECONE_ENVIRONMENT>"

export OPENAI_API_KEY="<OPENAI_API_KEY>"

export INDEX_NAME="<INDEX_NAME>"


PineconeのAPIキーEnvironmentの値は、API keysのページより取得します。


INDEX_NAMEは任意ですが、今回はcanopy-101としました。

こちらのCanopyのセットアップ動画でインデックス名をcanopy-101としているのですが、実際にPineconeに作成されるインデックスの名前はcanopy--が接頭辞として付加されるため、canopy--canopy-101になります。

以上の環境変数を設定した後に、Pineconeにインデックスを作成します。無料の範囲で利用する場合は、作成済みのインデックスがあれば削除しておく必要があります。

canopy new

[opc@canopy-rag ~]$ canopy new

Canopy is going to create a new index: canopy--canopy-101

Do you want to continue? [y/N]: y

Success!

[opc@canopy-rag ~]$ 


canopy newが成功するとPineconeのインデックスが作成されています。Pineconeのコンソールより、作成されたインデックスを確認できます。


Githubに記載されているCanopyのインストール手順では、この後より知識として扱われるドキュメントをPineconeのインデックスに登録する作業が続きます。

今回はAPEXのアプリケーションにRAGで使用するドキュメントの登録機能を実装します。そのため、Canopyのインストール作業は以上で完了です。

これより、HTTPSによる接続を受け付けるリバース・プロキシをNginxで構成します。DNSでパブリックIPアドレスの解決ができるようになっていることが前提です。

Oracle Cloudの仮想クラウド・ネットワークのパブリック・ネットワークのイングレス・ルールで、ポート80と443への接続が許可されていることを確認します。


Let's Encryptを使って証明書を発行します。

sudo certbot certonly --standalone

[opc@canopy-rag ~]$ sudo certbot certonly --standalone

Saving debug log to /var/log/letsencrypt/letsencrypt.log

Enter email address (used for urgent renewal and security notices)

 (Enter 'c' to cancel): <申請者のメール・アドレス>


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Please read the Terms of Service at

https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must

agree in order to register with the ACME server. Do you agree?

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(Y)es/(N)o: Y


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Would you be willing, once your first certificate is successfully issued, to

share your email address with the Electronic Frontier Foundation, a founding

partner of the Let's Encrypt project and the non-profit organization that

develops Certbot? We'd like to send you email about our work encrypting the web,

EFF news, campaigns, and ways to support digital freedom.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(Y)es/(N)o: N

Account registered.

Please enter the domain name(s) you would like on your certificate (comma and/or

space separated) (Enter 'c' to cancel): <DNSに登録したホスト名>

Requesting a certificate for host-name


Successfully received certificate.

Certificate is saved at: /etc/letsencrypt/live/host-name/fullchain.pem

Key is saved at:         /etc/letsencrypt/live/host-name/privkey.pem

This certificate expires on 2024-02-27.

These files will be updated when the certificate renews.

Certbot has set up a scheduled task to automatically renew this certificate in the background.


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

If you like Certbot, please consider supporting our work by:

 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate

 * Donating to EFF:                    https://eff.org/donate-le

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

[opc@canopy-rag ~]$ 


certbotの実行に成功するとディレクトリ/etc/letsencrypt/live/ホスト名/以下に、秘密キーのファイルとしてprivkey.pem、発行された証明書を保存するファイルとしてfullchain.pemが作成されます。

Nginxの構成ディレクトリである/etc/nginx/conf.d/に、server.confとして以下を記述したファイルを作成します。<ホスト名>の部分は実際のホスト名に置き換えます。


以上の設定を行い、nginxを起動します。

sudo systemctl start nginx

[opc@canopy-rag ~]$ sudo systemctl start nginx

[opc@canopy-rag ~]$ 


Canopyを起動します。Canopyを起動する前に、必ず環境変数を設定しておきます。(以下の例では環境変数の設定をmac.envというファイルに書き込んでいます。)

canopy start

[opc@canopy-rag ~]$ . mac.env

[opc@canopy-rag ~]$ canopy start

🚨 Note 🚨

For debugging only. To run the Canopy server in production run the command:

gunicorn canopy_server.app:app --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers <num_workers>

Starting Canopy server on 0.0.0.0:8000

INFO:     Started server process [3900]

INFO:     Waiting for application startup.

2023-11-29 03:25:43,526 - MainProcess - canopy_server.app [INFO    ]:  Did not find config file. Initializing engines with default configuration

INFO:     Application startup complete.

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)


手元のブラウザより、https://ホスト名/docsにアクセスします。HTTPSのリクエストはNginxが受け付けますがCanopyに転送されているため、CanopyのAPI定義情報が表示されます。


この時点で、Canopyのサーバーが提供するREST APIを、Oracle APEXのアプリケーションから呼び出せる状態になりました。

このCanopyのサーバーに問合せを行う、Oracle APEXのアプリケーションを作成します。

最初に知識となる文章を保存する表CANOPY_DOCUMENTSを作成します。以下のDDLを実行します。
create table canopy_documents (
    id        number generated by default on null as identity
              constraint canopy_documents_id_pk primary key,
    source    varchar2(80 char) not null,
    text      clob not null
);

SQLワークショップSQLコマンドで実行します。

ドキュメントはPineconeのインデックスに登録され検索もPineconeで実施されるため、本来はAPEX側で表を作成してデータを保持する必要はありません。Oracle APEXでは、表があった方が速くアプリケーションを作成できるため、表を作成しています。


続いて以下のコードを実行し、パッケージUTL_CANOPY_APIを作成します。CanopyへのRAGを使った問い合わせ(Completions APIの呼び出し)、Pineconeのインデックスの検索(Query API)、RAGの知識となるドキュメントの登録と削除(Upsert/Delete API)を呼び出すプロシージャを作成しています。

アプリケーション作成ウィザードを開始します。アプリケーションの名前Canopy Appとします。

ホーム・ページ削除し、先ほど作成した表CANOPY_DOCUMENTSフォーム付き対話モード・レポートのページを追加します。

ページの追加をクリックし、対話モード・レポートを選択します。


ページ名はDocuments表またはビューCANOPY_DOCUMENTSを選択し、フォームを含めるチェックします。

ページの追加をクリックします。


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


アプリケーションが作成されます。

最初にアプリケーション定義置換に、置換文字列としてG_CANOPY_URL置換値としてCanopyが動作しているサーバーのエンドポイントURLを設定します。URLの末尾は/v1とします。

https://Canopyが動作しているホスト名/v1


ページ番号の表CANOPY_DOCUMENTS対話モード・レポートのページを開きます。

RAGのデータとして与えるドキュメントに含まれる改行が適切に表示されるように、列TEXTタイプリッチ・テキストに変更します。設定書式マークダウンです。


表CANOPY_DOCUMENTSへのドキュメントの挿入、更新、削除は、このままでも実行できます。表CANOPY_DOCUMENTSへのドキュメントの挿入、更新、削除を行うと同時に、同じドキュメントをCanopyに挿入、更新(Upsert APIなので挿入と更新は同じ処理になります)、削除を実行するプロセスを作成します。

ページ番号のフォームのページを開きます。

プロセス・ビューから作成済みのプロセスプロセス・フォームCanopy Document重複させます。このプロセスは、表CANOPY_DOCUMENTSへの操作が実装されています。


新たに作成されたプロセスの識別名前Manage Canopy Document設定ターゲット・タイプPL/SQLコードに変更し、挿入/更新/削除するPL/SQLコードとして以下を記述します。
declare
    l_response clob;
begin
    utl_canopy_api.manage_document(
        p_row_status => :APEX$ROW_STATUS
        ,p_id => :P2_ID
        ,p_source => :P2_SOURCE
        ,p_text => :P2_TEXT
        ,p_canopy_url => :G_CANOPY_URL
        ,p_response => l_response
    );
end;
失われた更新の防止オフ行のロックいいえを指定します。


以上で、RAGで使用する知識となるドキュメントを登録できるようになりました。

アプリケーションを実行して、ドキュメントを登録してみます。

ナビゲーション・メニューよりDocumentsを開き、作成をクリックします。


Oracle APEX 23.2の新機能のページをコピペして登録してみました。


プロセスの実行が成功していれば、表CANOPY_DOCUMENTSへの書き込みと同時にPineconeのインデックスcanopy--canopy-101への書き込みが行われています。


Pineconeのコンソールよりインデックスcanopy--canopy-101を確認すると、登録したドキュメントは1つですが、チャンク分割が行われて34のベクトルが登録されていることが確認できます。


登録した知識を使った問い合わせを行うページを作成します。

ページの作成を実行します。


空白ページを選択します。


ページ番号名前Completionsとします。それ以外はデフォルトのまま変更しません。

ページの作成をクリックします。


ページが作成されます。

問い合わせとなる文章を入力するページ・アイテムを作成します。

識別名前P3_USER_CONTENTタイプテキスト領域ラベルUser Contentとします。


送信ボタンを作成します。

識別ボタン名SUBMITラベル信とします。外観ホットオンにし、テンプレート・オプションWidthとしてStretchを選択します。

動作アクションはデフォルトのページの送信です。


問い合わせ結果を表示するページ・アイテムを作成します。

識別名前P3_ASSISTANT_CONTENTタイプテキスト領域ラベルAssistant Contentとします。


送信ボタンを押した時に実行されるプロセスを作成します。左ペインでプロセス・ビューを開き、新規にプロセスを作成します。

作成したプロセスの識別名前Call Completionsとします。タイプAPIの呼出しを選択し、設定パッケージとしてUTL_CANOPY_APIプロシージャまたはファンクションとしてCOMPLETIONSを選択します。

サーバー側の条件ボタン押下時SUBMITを指定します。


パラメータp_canopy_urlを選択し、アイテムとして置換文字列G_CANOPY_URLを指定します。


パラメータp_responseを選択し、パラメータ出力を無視オンにします。

パラメータp_responseには、CanopyのCompletions APIを呼び出した際に受け取った、生のJSONの応答を戻します。デバッグなどのために画面に表示したい場合は、ページ・アイテムを新規に作成して出力先に設定すると良いでしょう。


以上で実装は完了です。ページの保存と実行を行います。

User Contentとして「Oracle APEXの新機能を教えてください。」と入力して、送信をクリックしてみました。

納得いかない回答が返されました。


Pineconeのインデックスの検索結果を確認するページを作成します。

このページもCompletionsと同じく空白のページを作成し、質問文を入力するページ・アイテム、送信ボタン、検索結果を返すページ・アイテムを作成します。送信ボタンのクリックでUTL_CANOPY_API.QUERYを呼び出すプロセスを作成します。

作成するページのページ番号名前Queryとします。


検索文を入力するページ・アイテムは名前P4_QUERY_TEXTタイプテキスト領域ラベルQuery Textとします。


送信ボタンは、Completionsのページの送信ボタンと同じです。


検索結果を返すページ・アイテムは、名前P4_QUERY_RESULTタイプテキスト領域ラベルQuery Resultとします。


Queryには追加でTop Kを指定するページ・アイテムを作成します。

識別名前P4_TOP_Kタイプとして数値フィールドを選択します。ラベルTop Kとします。

検証必須の値オンにします。デフォルトタイプ静的を選択し、静的値として3を設定します。


送信ボタンを押した時に実行されるプロセスを作成します。

作成したプロセスの識別名前Call Queryとします。タイプAPIの呼出しを選択し、設定パッケージとしてUTL_CANOPY_APIプロシージャまたはファンクションとしてQUERYを選択します。

サーバー側の条件ボタン押下時SUBMITを指定します。

パラメータのp_canopy_urlp_responseが赤く表示されます。Completionsのページと同じく、p_canopy_urlにはアイテムとしてG_CANOPY_URLを設定し、p_responseパラメータ出力を無視します。


以上で実装は完了です。ページの保存と実行を行います。

Query Textとして「Oracle APEXの新機能を教えてください。」と入力して、送信をクリックしてみました。


パラメータのp_max_tokensとして十分に大きい値が設定されている必要があるようですが、Top Kで指定した数だけ、類似したベクトルが返されました。

大きなドキュメントを登録してCanopyにチャンク分割を任せたのが、納得いかない回答が生成される理由ではないかと推測しています。

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

Oracle Linux 9上に実装したnginxおよびCanopyの双方ともに、自動起動は実装していないため、作業をする際にはサーバーを毎回起動する必要があります。

以上になります。

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