作成したアプリケーションは以下のように動作します。
以前の記事よりパッケージUTL_CRED_GOOGLEを少し更新しています。サービス・アカウントの秘密キーより生成したJWTを一旦APEXのWeb資格証明として保存できるようにプロシージャcreate_or_update_jwt_credentialを追加しました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set serveroutput on | |
declare | |
C_RSA_KEY constant varchar2(32767) := q'~ | |
-----BEGIN PRIVATE KEY----- | |
サービス・アカウントに登録されている秘密キー | |
-----END PRIVATE KEY----- | |
~'; | |
l_jwt varchar2(32767); | |
l_token varchar2(32767); | |
begin | |
l_jwt := utl_cred_google.generate_jwt( | |
p_secret => C_RSA_KEY | |
-- サービス・アカウントのメールを指定。 | |
,p_iss => 'サービス・アカウントのメール' | |
); | |
dbms_output.put_line(l_jwt); | |
utl_cred_google.create_or_update_jwt_credential( | |
p_jwt => l_jwt | |
,p_jwt_credential_static_id => 'GOOGLE_GEMINI_API_JWT' | |
-- p_workspace_nameはワークスペースに合わせて変更 | |
,p_workspace_name => 'APEXDEV' | |
); | |
commit; | |
end; | |
/ |
保存したWeb資格証明GOOGLE_GEMINI_API_JWTを使ってアクセス・トークンを取得し、取得したアクセス・トークンをWeb資格証明GOOGLE_GEMINI_API_TOKENに保存します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_token varchar2(32767); | |
begin | |
utl_cred_google.create_or_update_apex_credential( | |
p_jwt_credential_static_id => 'GOOGLE_GEMINI_API_JWT' | |
,p_credential_static_id => 'GOOGLE_GEMINI_API_TOKEN' | |
,p_workspace_name => 'APEXDEV' -- ワークスペースに合わせて変更 | |
,p_token => l_token | |
); | |
-- dbms_output.put_line(l_token); | |
commit; | |
end; | |
/ |
以前の記事で作成したバケット(名前はmy-gemini-data-1234)に権限を追加します。
新しいプリンシパルにVertex AI Gemini APIにアクセスするために作成したサービス・アカウントのメールを指定し、ロールにStorageオブジェクトユーザーを指定します。
作成をクリックして、権限を追加します。
Google Cloud Storageの準備は以上です。
空のアプリケーションを作成します。名前はSample Google Object Storage JSON APIとします。
OpenAPIによるドキュメントがあれば、それを基にRESTデータ・ソースを作成することができるので、Google Bardに聞いてみました。無いみたいです。
APIのリファレンスより、最初からRESTデータ・ソースを作成することにします。
データ・ソース・タイプとして簡易HTTPを選びます。名前はGoogle Cloud Storage JSON APIとします。
URLパラメータ1としてbucketが認識されます。値にmy-gemini-data-1234を設定します。これはデフォルト値になります。RESTデータ・ソースを作成した後に変更することも可能です。
認証が必要ですをオンにし、静的IDがGOOGLE_GEMINI_API_TOKENであるWeb資格証明を選択します。
バケットには最低でも1つファイルをアップロードしておきます。ファイルがないとレスポンスに含まれる列が自動検出されません。
共有コンポーネントのRESTデータ・ソースを開きます。
作成をクリックします。
RESTデータ・ソースの作成として最初からを選びます。
次へ進みます。
URLエンドポイントは以下を指定します。バケット名の部分は:bucketとし、URLパラメータとして認識させます。
https://storage.googleapis.com/storage/v1/b/:bucket/o
URLパラメータ1としてbucketが認識されます。値にmy-gemini-data-1234を設定します。これはデフォルト値になります。RESTデータ・ソースを作成した後に変更することも可能です。
次へ進みます。
自動的に設定されるベースURLなどを確認します。通常は変更不要です。
次へ進みます。
APIの仕様から、パラメータstartOffset、endOffset、pageToken、maxResultsに値を指定することによりページングが可能なようです。APEXが提供しているページ区切りタイプで、これらのパラメータを扱える設定がないのため、ページ区切りタイプとしてページ区切りなしを選択します。
今回の用途ではほとんどバケットにファイルを配置しないためページングを実装する必要はありませんが、maxResultsの推奨値が1000となっているので(デフォルト値は不明)、それ以上のファイルをバケットに含める場合はページングの実装が必要になりそうです。
次へ進みます。
検出をクリックします。
バケット中のファイルが一覧されていることを確認します。
RESTデータ・ソースの作成をクリックします。
RESTデータ・ソースGoogle Cloud Storage JSON APIが作成されます。
作成されたRESTデータ・ソースGoogle Cloud Storage JSON APIを編集します。
操作の追加をクリックします。
URLパターンとして/:object、HTTPメソッドとしてDELETE、データベース操作として行の削除を選択します。
作成をクリックします。
URLパターンに含めた:objectをパラメータとして設定します。
タイプはURLパターン、名前はobject、静的はオフ、データ型は文字列です。必須をオンにします。
パラメータの追加をクリックします。
行の挿入の操作を追加します。行の削除のときと同様に、操作の追加をクリックします。
APIリファレンスとしては以下を参照します。ただし、Object StorageへのファイルのアップロードlはRESTデータ・ソースには実装せず、別にプロセスを作成して実装します。
HTTPメソッドとしてPOST、データベース操作として行の挿入を設定します。
作成をクリックします。
パラメータbucketを編集します。
編集の鉛筆アイコンをクリックします。
変更の適用をクリックします。
今回は省略しますが、Google Cloud StorageのObjectsのResource representationsを参照して、データ・プロファイルを調整することにより、フォームに自動生成されるページ・アイテムをより適切に生成することができます。
データ・プロファイルの編集を開きます。
データ型がVARCHAR2の列が複数検出されています。
自動検出されたこれらの列の設定を確認すると、長さがPL/SQLのVARCHAR2の最大値32767になっています。そのため大抵の場合、この列に対応するページ・アイテムはタイプがテキスト領域になります。
RESTデータ・ソースの編集を完了します。
変更の適用をクリックします。
作成したRESTデータ・ソースを基にした、対話モード・レポートとフォームのページを作成します。
ページの作成をクリックします。
対話モード・レポートを選択します。
対話モード・レポートのページの名前はFilesとします。ページ番号は2です。フォーム・ページを含めるをオンにし、フォーム・ページ名としてFileを設定します。フォームのページ番号は3とします。
データ・ソースとしてRESTデータ・ソースを選択し、RESTデータ・ソースに先ほど作成したGoogle Cloud Storage JSON APIを選択します。
ナビゲーションはデフォルトから変更せず、ブレッドクラムの使用、ナビゲーションの使用ともにオンにします。
次へ進みます。
主キー列1としてID (Varchar2)を指定します。
ページの作成をクリックします。
対話モード・レポートとフォームのページが作成されます。
対話モード・レポートのパラメータbucketを選択し、値の静的値に&G_BUCKET_NAME.を設定します。
RESTデータ・ソースが呼び出される際に、パラメータbucketに置換文字列G_BUCKET_NAMEに設定した値(今回の例ではmy-gemini-data-1234)が渡されます。
保存をクリックします。
フォームのパラメータbucketについても、値の静的値として&G_BUCKET_NAME.を設定します。
フォームのパラメータobjectの値として、タイプはアイテム、アイテムはP3_NAMEを指定します。
左ペインでプロセス・ビューを開きます。
ページ作成ウィザードによって作成されたプロセスプロセス・フォームFileは、削除処理のみを実行します。
サーバー側の条件のボタン押下時にDELETEを設定します。
また、今回のRESTデータ・ソースでは失われた更新の防止や行のロックは実装できません。失われた更新の防止はオフ、行のロックはいいえ、挿入後に主キーを返すはオフに変更します。
左ペインでレンダリング・ビューを表示します。
アップロードするファイルを選択するページ・アイテムを作成します。
識別の名前はP3_FILES、タイプはファイルのアップロード、ラベルはFilesとします。
ストレージのタイプは表APEX_APPLICATION_TEMP_FILES、ファイルをパージするタイミングはリクエストの終わりを選択します。一度に複数のファイルをアップロードできるように、複数ファイルの許可をオンにします。
セッション・ステートのストレージはリクエストごと(メモリーのみ)とします。
作成ボタンを押してフォームを開いたときに限り、このページ・アイテムが表示されるよう、サーバー側の条件のタイプにアイテムはNULLを選択し、アイテムとしてP3_IDを指定します。
ページ・アイテムP3_IDとP3_FILESを除いたすべてのページ・アイテムは、ファイルのアップロード時に表示する必要がありません。
これらのページ・アイテムをすべて選択します。サーバー側の条件のタイプにアイテムはNULLではないを選択し、アイテムとしてP3_IDを指定します。
左ペインでプロセス・ビューを開きます。
ファイルをアップロードするプロセスを作成します。
識別の名前はUpload Files、タイプはコードを実行とします。
ソースのPL/SQLコードとして以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_uri varchar2(32767); | |
l_response clob; | |
e_upload_failed exception; | |
begin | |
for r in ( | |
select * from apex_application_temp_files | |
where name in ( | |
select column_value from apex_string.split(:P3_FILES,':') | |
) | |
) | |
loop | |
l_uri := 'https://storage.googleapis.com/upload/storage/v1/b/' || :G_BUCKET_NAME || '/o?name=' | |
|| utl_url.escape(r.filename, false, 'AL32UTF8') | |
|| '&uploadType=media'; | |
apex_web_service.clear_request_headers(); | |
apex_web_service.set_request_headers('Content-Type', r.mime_type, p_reset => false); | |
apex_web_service.set_request_headers('Content-Length', dbms_lob.getLength(r.blob_content), p_reset => false); | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_uri | |
,p_http_method => 'POST' | |
,p_body_blob => r.blob_content | |
,p_credential_static_id => :G_CREDENTIAL | |
); | |
if apex_web_service.g_status_code <> 200 then | |
raise e_upload_failed; | |
end if; | |
end loop; | |
end; |
サーバー側の条件のボタン押下時にCREATEを指定します。
ページを保存します。
Googleのサービス・アカウント・キーを使って取得したアクセス・トークンの有効期限は最長で1時間のようで、アクセス・トークンを更新する仕組みは別途実装する必要があるでしょう。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-google-object-storage-json-api.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完