セットアップ
ローカルでの実行のためのセットアップを行います。
前提条件
- Python3.11以降の実行環境
- Agora開発者用プロジェクト
- OpenAIアカウント及びopen api key
サンプルコード
この統合SDKは既にサンプルコードが用意されており、短時間で実行して検証することができます。
以下はデモをローカルで実行するための参考資料です。
基本的にはgithubのREADMEに従うことで実装が可能です。
ここにも記載されていますが、ネットワークアーキテクチャは以下の通りであり、本記事では図中の用語を使用します。
クイックスタートやREADME通りに必要なパッケージのインストールや環境変数の設定などを終え、実行を行っていきます。
また、今回は LLM に GPT-4o を採用します。
実行
実行手順については様々ありますが流れの一例を紹介します。
手順
このデモを利用するために、まずは End User Client 側の Frond-end App を用意し、ユーザーを先にAgoraのチャンネルに入室させておきます。
ここでは簡易的に、Agoraが提供している音声通話を行うデモサイトを用います。
そのため、今回はアーキテクチャ図中の Developer Server にリクエストを送る作業は別途行います。
Web demo : https://webdemo.agora.io/basicVoiceCall/index.html
続いて、Developer Server を起動させます。
$ python3 -m realtime_agent.main server
その後別のCLIから Developer Server への開始リクエストを送ります。
この時、channel_nameはWeb demoに入室したチャンネルと同一です。
curl 'http://localhost:8088/start_agent' \
-H 'Content-Type: application/json' \
--data-raw '{
"channel_name": "test_channel",
"uid": 123
}';
以上、ここまでの手順で Web demo で入室しているユーザーの発言に対し、openAIが会話を返してくれます。
また、終える際には終了のリクエストを送ります。
curl 'http://localhost:8088/stop_agent' \
-H 'Content-Type: application/json' \
--data-raw '{
"channel_name": "test_channel"
}'
(補足)
ローカルで検証する際、以下のコマンドで Developer Server の立ち上げと開始を同時に行うことができます。
openai-realtime-python % python -m realtime_agent.main agent --channel_name=test_channel --uid=123
検証
上記の手順で試すと、Web demo 側に日本語の音声できちんと返事が返ってくることが分かります。
また、サンプルではターミナルにログを出力するようになっています。
試しに挨拶をしてこれを確認し、それぞれの時刻を確認してみます。
11:40:17,116 発言の開始
1140:18:107 発言の終了
11:40:18,702 リクエスト「こんにちは」
11:40:19,020 レスポンス「こんにちは!今日はどんなお手伝いをしましょうか?」
発言の終了からレスポンスが返ってくるまで、わずか0.913秒でした。
非常にリアルタイムな対応ができることがわかります。
これはAgoraの超低遅延なインフラと音声情報を音声情報のまま処理するRealtime APIの強みです。
(参考)fast.comで計測した検証環境のネットワーク
チャットテキストの表示
既に音声でのスムーズな会話が実現できました。
最後に、より実用的なサービスとして近づけるために会話のテキストをリアルタイムに描画してみます。
実装
用意されている統合SDKは、既にオーディオストリームと併せて扱っている情報をUInt8Array型でAgoraのチャンネルへ流しています。
なのでこのデータの受信及びブラウザへの描画を行うことができれば上記が実現できます。
Agoraの公式サイトより上述のWeb demoとほぼ同様のソースコードをダウンロードできるため、今回はこちらをアレンジする形で実装を行います。
Download SDKs : https://docs.agora.io/en/sdks?platform=web
メッセージを受け取った際のイベントハンドラを設定
client.on("stream-message", handleUserStreamMessage);
イベントハンドラの処理内容
function handleUserStreamMessage(uid, payload) {
try {
//UInt8Array型をテキストに変換する
const textDecoder = new TextDecoder('utf-8');
const message = textDecoder.decode(payload);
// Base64部分を分離してデコード
const base64Part = message.split('|')[3];
const decodedText = atob(base64Part);
const data = JSON.parse(decodedText);
const transcript = data.transcript;
let role = "";
if (data.type === "conversation.item.input_audio_transcription.completed") {
role = "あなた:";
} else if (data.type === "response.audio_transcript.done") {
role = "相手:";
} else {
return;
}
const paragraph = document.createElement("p");
paragraph.textContent = role + transcript;
document.getElementById("chat-area").appendChild(paragraph);
} catch (error) {
console.error(`Failed to process message from UID ${uid}:`, error);
}
結果
簡易的ではありますが、自身の話した内容と、Realtime APIからの返答がそれぞれ描画されていることが確認できました。