2025年10月8日水曜日

ElevenLabsのAPIをAPEXアプリケーションから呼び出してSpeech-to-TextとText-to-Speechを実行する

AIを活用した音声合成のプラットフォームとして、評価の高い会社のひとつにElevenLabsがあります。ElevenLabsが提供しているサブスクリプションにFreeプランがあり、基本的な動作確認は無料で実施できます。

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 RecorderStart/Stopで、音声の録音の開始と停止を行います。Transcribeで、録音した音声からテキストを起こします。Create Speechで、表示されているテキストを、選択したVoice IDで読み上げます。生成された音声はVoice Recorderに設定されます。そのため、ElevenLabsのAPIを呼び出して生成されたスピーチは、音声プレーヤーで再生できます。


作成したAPEXアプリケーションのエクスポートを以下に置きました。
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静的IDELEVENLABS_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データ・ソースの作成最初から実施します。へ進みます。


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"が含まれているJessicaGeorgeAliceは期待できます。この話者はHigh Quality Base Model Idseleven_multilingual_v2が含まれています。


Create speech APIを呼び出す際に、引数にVOICE_IDを含める必要があります。ページ上でVOICE_IDを選択できるように、このRESTデータ・ソースから共有コンポーネントのLOVを作成します。

共有コンポーネントLOVを開きます。


LOVの作成を開始します。


LOVの作成最初からを選択し、へ進みます。


名前Voicesとします。タイプDynamicを選びます。

へ進みます。


データ・ソースRESTソースを選び、RESTデータ・ソースとしてElevenLabs List voicesを選択します。

へ進みます。


戻り列VOICE_ID表示列NAMEを選択します。

以上で作成をクリックします。


LOVとしてVoicesが作成されます。LOVの項目を表示する際に、ローカル表を参照するように設定を変更するため、LOVを編集します。


拡張RESTデータ・ソース属性同期化表の使用オンにします。また、音声の選択を容易にするために、追加表示列を設定します。列の選択をクリックします。


追加列としてLABELS_AGE、LABELS_ACCENT、LABELS_GENDER、LABELS_LANGUAGE、LABELS_USE_CASE、LABELS_DESCRIPTIVE、DESCRIPTIONを追加します。これらはすべて表示可能および検索可能はいにします。


以上で変更の適用をクリックし、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

また、ナビゲーション保存されていない変更の警告オフにします。


ブラウザ上でボタンをクリックすると、静的アプリケーション・ファイルimproved_voice_recorder.jsに記述されたAPEXアクションが呼び出されます。APEXアクションからapex.server.processを使ってAjaxコールバックが呼び出されます。そしてAjaxコールバックのPL/SQLコードの中から、APEX_WEB_SERVICE.MAKE_REST_REQUESTを使ってElevenLabsのREST APIが呼び出されます。

AjaxコールバックとしてTRANSCRIBEを作成し、ソースPL/SQLコードとして以下を記述します。Create transcript APIを呼び出します。



AjaxコールバックとしてCREATE_SPEECHを作成し、ソースPL/SQLコードとして以下を記述します。Create speeh APIを呼び出します。



この他にAjaxコールバックとしてCREATE_VOICEを作成しています。ボイス・クローンを作成するCreate IVC voice APIを呼び出していますが、購読の関係で動作は確認できていません。



JavaScriptのコードとPL/SQLのコードについては、すべてアプリケーションに含めることができました。

残りはページのデザインになります。

オーディオ・プレーヤーと録音の開始、終了ボタンを配置するリージョンを作成します。名前Voice Recorderタイプ静的コンテンツ外観テンプレートStandardです。


録音の開始、終了のボタンを配置するリージョンを作成します。名前Button Containerレイアウト親リージョンVoice RecorderスロットRegion Body外観テンプレートButton Containerとします。


リージョンButton Containerに録音を開始するボタンSTARTを作成します。動作アクション動的アクションで定義とし、詳細カスタム属性に以下を設定します。

data-action="start-voice-recording"


同様に録音を停止するボタンSTOPを作成します。カスタム属性として以下を設定します。

data-action="stop-voice-recording"


オーディオ・プレーヤーを配置するリージョンを作成します。名前RecorderソースHTMLコードに以下を記述します。

<audio id="recorder" controls></audio>

装飾をなくすために外観テンプレート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として作成します。タイプポップアップLOVLOVタイプ共有コンポーネントを選択し、LOVとしてVOICESを設定します。追加値の表示オフにします。


以上でAPEXアプリケーションは完成です。

ElevenLabsのText-to-SpeechおよびSpeech-to-Textの両方のAPIを呼びことはできましたが、やはりストリーミングが扱えないとアプリケーションとしての使い勝手はやや下がります。

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

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