2023年1月24日火曜日

OpenAI Whisperを使った文字起こしアプリの作成(4) - APEXアプリの作成

 Whisperによる文字起こしを行うAPIが作成できました。このAPIを呼び出すAPEXアプリケーションを作成します。

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

アプリケーション作成ウィザードを起動します。

名前Whisper Transcribeとします。すべての機能はデフォルトで作成されるホーム・ページに実装します。そのため、設定は変更せずにアプリケーションの作成を実行します。

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

ページ・デザイナにてホーム・ページを開きます。

最初に音声ファイルを指定するページ・アイテムを作成します。

Bodyにページ・アイテムを作成します。

識別名前P1_FILEタイプとしてファイル参照...を選択します。

設定ファイルをパージするタイミングとして、End of Requestを選択します。セッション・ステートストレージとしてリクエストごと(メモリーのみ)を選択します。

音声ファイルのアップロードとAPI呼び出しによる文字起こしは、1回のHTTPリクエストで完結します。そのため、アップロードした音声ファイルを処理完了後に保持する必要はありません。

音声ファイルのアップロードと文字起こしを実行するボタンを作成します。

作成したボタンのボタン名SUBMITラベルSubmitとします。動作アクションはデフォルトでページの送信になります。


文字起こしの結果を保持するページ・アイテムを作成します。

作成したページ・アイテムの識別名前P1_TEXTタイプとしてテキスト領域を選択します。ラベルTextとします。

セッション・ステートデータ型CLOBストレージとしてセッションごと(永続)を選択します。このように設定すると、ページをリロードしても文字起こしの結果が維持されます。


ボタンSUBMITをクリックしたときに、文字起こしのAPIを呼び出す処理を実装します。

以下のコードを実行し、パッケージUTL_WHISPERを作成します。

create or replace package utl_whisper
as
/**
* 音声データをアップロードし、Whisperの文字起こしを実装したAPIを呼び出す。
*
* @param p_url Whisper APIのエンドポイントURL
* @param p_file APEX_APPLICATION_TEMP_FILESのnameとなるファイル名
* @param p_text Whisperによって、音声より文字起こしされた文字列。
*/
procedure transcribe(
p_url in varchar2
,p_file in varchar2
,p_text out clob
);
end utl_whisper;
/
create or replace package body utl_whisper
as
procedure transcribe(
p_url in varchar2
,p_file in varchar2
,p_text out clob
)
as
l_filename apex_application_temp_files.filename%type;
l_blob_content blob;
l_multipart apex_web_service.t_multipart_parts;
l_multipart_request blob;
l_response clob;
l_response_json json_object_t;
l_segments json_array_t;
l_count pls_integer;
l_segment json_object_t;
l_temp_clob clob;
l_text varchar2(32767);
begin
/* APEXにアップロードされた音声データをBLOBに取り出す。 */
select filename, blob_content into l_filename, l_blob_content
from apex_application_temp_files
where name = p_file;
/*
* 取り出した音声データをmultipart/form-dataとして、WhisperのAPIを呼び出す。
*/
apex_web_service.clear_request_headers;
/* WhisperのAPI側ではファイル名もMIMEタイプも確認していない。 */
apex_web_service.append_to_multipart(
p_multipart => l_multipart
,p_name => 'file'
,p_filename => l_filename
,p_content_type => 'application/octet-stream'
,p_body_blob => l_blob_content
);
l_multipart_request := apex_web_service.generate_request_body(l_multipart);
l_response := apex_web_service.make_rest_request(
p_url => p_url
,p_http_method => 'POST'
,p_body_blob => l_multipart_request
);
/* デバッグでJSON自体を見たいときは、l_responseを確認する。 */
-- p_text := l_response;
l_response_json := json_object_t(l_response);
/*
* 返されたJSONデータより、文字起こしされたテキストを取り出す。
*/
/* そのまま取り出しても、文字起こしの結果としては同じ。 */
-- p_text := l_response_json.get_string('text');
/* segmentsの配列から取り出す、手間のかかる方法。 */
l_segments := l_response_json.get_array('segments');
l_count := l_segments.get_size();
dbms_lob.createTemporary(l_temp_clob, false, DBMS_LOB.CALL);
for i in 0..(l_count - 1)
loop
l_segment := treat(l_segments.get(i) as json_object_t);
l_text := l_segment.get_string('text');
dbms_lob.writeappend(
lob_loc => l_temp_clob
,amount => length(l_text)
,buffer => l_text
);
end loop;
p_text := l_temp_clob;
dbms_lob.freeTemporary(l_temp_clob);
end transcribe;
end utl_whisper;
/
view raw utl_whisper.sql hosted with ❤ by GitHub
左ペインでプロセス・ビューを開き、文字起こしのAPIを呼び出すプロセスを作成します。

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

サーバー側の条件ボタン押下時SUBMITを選択し、ボタンが押されたときにUTL_WHISPERのプロシージャTRANSCRIBEが呼び出されるようにします。


パラメータのp_filep_textはデフォルトでページ・アイテムP1_FILEP1_TEXTが割り当たります。

パラメータp_urlは、タイプアイテムアイテムとしてG_TRANSCRIBE_URLを指定します。G_TRANSCRIBE_URLは置換文字列として、この後に値を設定します。


アプリケーション定義置換を開き、置換文字列をG_TRANSCRIBE_URLとして、置換値にWhisperによる文字起こしを行うAPIを実装したURLを設定します。


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

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

無料の範囲だと処理に時間がかかるため、実用レベルで使用するのは難しいとは思います。とはいえ、どのように使えるのかという評価はできるのではないでしょうか。

次の記事で、JavaScriptから直接Whisperを呼び出すような実装を追加します。

続く