ElevenLabsに限らず、大抵のサービスではPL/SQLのSDKは提供されていません。そのため、これらのサービスをAPEXから利用するには、REST APIの仕様を確認してAPIを呼び出すコードをPL/SQLで書く必要があります。本記事では、ElevenLabsのText-to-SpeechとSpeech-to-TextのAPIを呼び出すAPEXアプリケーションを作成します。本当はElevenLabsのIVC - インスタント・ボイス・クローニングを使ってみたかったのですが、IVCを使うには最低でもStarterプランを購読する必要があるため、Freeプランでは利用できませんでした。少し残念です。
音声がないので何をやっているのか分かりませんが、作成したAPEXアプリケーションは以下のように動作します。Voice RecorderのStart/Stopで、音声の録音の開始と停止を行います。Transcribeで、録音した音声からテキストを起こします。Create Speechで、表示されているテキストを、選択したVoice IDで読み上げます。生成された音声はVoice Recorderに設定されます。そのため、ElevenLabsのAPIを呼び出して生成されたスピーチは、音声プレーヤーで再生できます。
https://github.com/ujnak/apexapps/blob/master/exports/sample-elevenlabs-tts-stt.zip
以下より作成したアプリケーションを紹介します。
ElevenLabsのAPIを呼び出すには、開発者としてElevenLabsにサインアップし、最低でもFreeプランを購読する必要があります。プランを購読するとAPIキーを発行できます。
APEXからElevenLabsのAPIを呼び出すにあたって、このAPIキーをWeb資格証明として作成します。本記事では名前をElevenLabs API Key、静的IDをELEVENLABS_API_KEYとして、Web資格証明を作成しています。静的IDについては、PL/SQLのコードに直書きしているため、違う静的IDにした場合はコードの変更が必要になります。
ElevenLabsのAPIキーは、HTTPヘッダーxi-api-keyの値として送信します。そのため、Web資格証明の認証タイプにHTTPヘッダーを選択し、資格証明名はHTTPヘッダー名であるxi-api-key、資格証明シークレットにAPIキーを設定します。
URLに対して有効にElevenLabsのAPIエンドポイントであるhttps://api.elevenlabs.io/を設定し、認証情報が誤って異なるサイトに送信されることを防ぎます。
空のAPEXアプリケーションを作成します。名前はElevenLabsとします。
アプリケーションが作成されます。
ElevenLabsでは、テキストの読み上げに使用できる音声を選択できます。使用できる音声を一覧するAPIが提供されていますが、音声を選択するたびにAPIを発行することは避けたいです。そのため、音声の一覧をRESTデータ・ソースとして取得できるようにし、ローカル表との同期を構成します。
共有コンポーネントのRESTデータ・ソースを開きます。
RESTデータ・ソースの作成は最初から実施します。次へ進みます。
RESTデータ・ソース・タイプに簡易HTTPを選択し、名前はElevenLabs List voicesとします。
URLエンドポイントとして以下を設定します。
https://api.elevenlabs.io/v2/voices
次へ進みます。
リモート・サーバーの設定になります。リモート・サーバーとしてhttps://api.elevenlabs.io/が作成済みの場合は、それが選択されます。まだ作成されていない場合は、リモート・サーバーとしてhttps://api.elevenlabs.io/が作成されます。
次へ進みます。
ページ区切りを以下のように設定します。
ページ区切りタイプ: ページ・サイズとページ・トークン
ページ・サイズURLパラメータ:page_size
ページ・サイズ最大:100
ページ・トークンURLパラメータ:next_page_token
次のページ・トークン・セレクタ:next_page_token
その他の行セレクタ:has_more
次の値のときのその他の行:次と等しい
その他の行属性値:true
合計行セレクタ:total_count
次へ進みます。
認証が必要ですをオンにし、資格証明としてすでに作成しているElevenLabs API Keyを選択します。
以上で検出を実行します。
APIを呼び出して得られた音声の一覧が表示されます。
RESTデータ・ソースの作成をクリックします。
RESTデータ・ソースElevenLabs List voicesが作成されます。
同期化を設定するために、作成されたRESTデータ・ソースElevenLabs List voicesを開きます。
右端のメニューより同期化の管理を開きます。
同期先に新規表を選び、表名にELEVENLABS_VOICESを指定します。
保存をクリックします。
同期化表が存在しません、と表示されています。表の作成をクリックします。
表ELEVENLABS_VOICESが作成されます。詳細の同期タイプに置換を選択し、保存して実行をクリックします。
今回は使用できる音声に変更あれば手動で同期することを想定しているため、同期タイプを置換にしています。定期的に同期する場合は、一般に追加またはマージを選択します。
同期処理の結果はログに表示されます。ステータスが成功であれば、同期が完了しています。
以上でRESTデータ・ソースが作成できました。
使用できる音声を確認するために、対話モード・レポートのページを作成します。
ページの作成を開始します。
対話モード・レポートを選択します。
ページの名前はVoicesとします。データ・ソースとしてRESTソースを選び、RESTデータ・ソースにElevenLabs List voicesを選択します。
ページの作成をクリックします。
対話モード・レポートのリージョンを選択し、REST同期化のローカル表の使用をオンにします。これで、対話モード・レポートはローカル表を参照するようになり、レポートの表示の際にREST APIは発行されなくなります。
以上で音声を一覧するページは完成です。ページを実行して選択できる音声を確認します。
日本語話者はいないようですが、Verified Languagesに"language": "ja"が含まれているJessica、George、Aliceは期待できます。この話者はHigh Quality Base Model Idsにeleven_multilingual_v2が含まれています。
共有コンポーネントのLOVを開きます。
LOVの作成を開始します。
LOVの作成は最初からを選択し、次へ進みます。
名前はVoicesとします。タイプはDynamicを選びます。
次へ進みます。
データ・ソースにRESTソースを選び、RESTデータ・ソースとしてElevenLabs List voicesを選択します。
次へ進みます。
戻り列にVOICE_ID、表示列にNAMEを選択します。
以上で作成をクリックします。
LOVとしてVoicesが作成されます。LOVの項目を表示する際に、ローカル表を参照するように設定を変更するため、LOVを編集します。
拡張RESTデータ・ソース属性の同期化表の使用をオンにします。また、音声の選択を容易にするために、追加表示列を設定します。列の選択をクリックします。
以上で変更の適用をクリックし、LOVの作成を完了します。
準備作業は以上で完了です。
ホーム・ページにText-to-SpeechとSpeech-to-Textを行なう機能を実装します。
共有コンポーネントの静的アプリケーション・ファイルとしてimproved_voice_recorder.jsを作成します。ファイルの内容は以下です。一通り動くところまでは自分でコードを書いたのち(静的アプリケーション・ファイルのapp.jsとして残しています)、Claude Sonnet 4.5に書き直してもらっています。
ページ・プロパティのJavaScriptのファイルURLに、静的アプリケーション・ファイルの参照を記述します。
[module]#APP_FILES#improved_voice_recorder#MIN#.js
AjaxコールバックとしてTRANSCRIBEを作成し、ソースのPL/SQLコードとして以下を記述します。Create transcript APIを呼び出します。
AjaxコールバックとしてCREATE_SPEECHを作成し、ソースのPL/SQLコードとして以下を記述します。Create speeh APIを呼び出します。
この他にAjaxコールバックとしてCREATE_VOICEを作成しています。ボイス・クローンを作成するCreate IVC voice APIを呼び出していますが、購読の関係で動作は確認できていません。
残りはページのデザインになります。
オーディオ・プレーヤーと録音の開始、終了ボタンを配置するリージョンを作成します。名前はVoice Recorder、タイプは静的コンテンツ、外観のテンプレートはStandardです。
録音の開始、終了のボタンを配置するリージョンを作成します。名前はButton Container、レイアウトの親リージョンはVoice Recorder、スロットはRegion Body、外観のテンプレートはButton Containerとします。
リージョンButton Containerに録音を開始するボタンSTARTを作成します。動作のアクションを動的アクションで定義とし、詳細のカスタム属性に以下を設定します。
data-action="start-voice-recording"
装飾をなくすために外観のテンプレートにBlank with Attributesを選択します。
Speech-to-Textの結果のテキストが保存されるページ・アイテムであり、Text-to-Speechのソースとなるテキストを保持するページ・アイテムとしても使用するページ・アイテムP1_TEXTを作成します。タイプはテキスト領域です。
Speech-to-Textの実行結果(テキストはP1_TEXTに表示)を表示するリージョンを作成します。このリージョンにはSpeech-to-Textを実行するボタンも配置します。
名前はTranscribe、タイプは静的コンテンツ、外観のテンプレートにStandardを選択します。
Speech-to-Textを実行するボタンTRANSCRIBEを作成します。レイアウトのスロットにCopyを選択します。
動作のアクションは動的アクションで定義とし、詳細のカスタム属性に以下を記述します。
data-action="transcribe"
ページ・アイテムP1_LANGUAGE_CODEを作成します。Speech-to-Textで認識された言語を表示します。
ページ・アイテムP1_LANGUAGE_PROBABILITYを作成します。Speech-to-Textで検出された言語(P1_LANGUAGE_CODEに表示されている言語)の確かさを表す数値を表示します。
Text-to-Speechに与えるVOICE_IDを設定するリージョンを作成します。このリージョンにはText-to-Speechを実行するボタンも配置します。
名前はSpeech、タイプは静的コンテンツ、外観のテンプレートにStandardを選択します。リージョンTranscribeの右隣に配置するため、レイアウトの新規行の開始はオフにします。
Text-to-Speechを実行するボタンCREATE_SPEECHを作成します。レイアウトのスロットにCopyを選択します。
動作のアクションは動的アクションで定義とし、詳細のカスタム属性に以下を記述します。
data-action="create-speech"
Text-to-Speechの話者を選択するページ・アイテムをP1_VOICE_IDとして作成します。タイプはポップアップLOV、LOVのタイプに共有コンポーネントを選択し、LOVとしてVOICESを設定します。追加値の表示はオフにします。
以上でAPEXアプリケーションは完成です。
ElevenLabsのText-to-SpeechおよびSpeech-to-Textの両方のAPIを呼びことはできましたが、やはりストリーミングが扱えないとアプリケーションとしての使い勝手はやや下がります。
今回の記事は以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完