OpenAIのRealtime APIを使って、AIとのリアルタイム会話を検証してみました。
WebRTCを活用することで、従来の「録音 → 送信 → 処理 → 返信」というステップを排除し、「話しながら同時に処理する」という圧倒的な低遅延体験が可能です。
今回作るものの構成
- サーバー側 (Laravel): APIキーを隠蔽し、安全な「一時的なトークン(Ephemeral Token)」を発行する。
※苦肉の策です。実運用となるとセキュリティを検討する必要があります。 - フロント側 (WebRTC): ブラウザのマイク音声をOpenAIにストリーミング送信し、返ってきた音声データを再生する。
1. サーバー側の準備:セッション・トークンの発行
APIキーを直接フロントエンドに書くのは非常に危険です。OpenAI Realtime APIには、1分間だけ有効なクライアント用トークンを発行するエンドポイントがあります。
Controllerの作成
app/Http/Controllers/RealtimeController.phpnamespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
class RealtimeController extends Controller
{
public function index() {
return view('realtime.index');
}
public function token() {
$apiKey = env('OPENAI_API_KEY');
// OpenAIにセッション開始をリクエスト
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
])->post('https://api.openai.com/v1/realtime/sessions', [
'model' => 'gpt-4o-mini-realtime-preview-2024-12-17',
'voice' => 'alloy', // 声のタイプ
'instructions' => 'あなたは親切なAIアシスタントです。日本語で自然に会話してください。',
]);
return $response->json();
}
}2. フロントエンドの実装:WebRTCによるリアルタイム接続
ブラウザのRTCPeerConnectionを使ってOpenAIと直接つながります。
Viewの作成(抜粋)
resources/views/realtime/index.blade.php JavaScriptの主要な処理フローは以下の通りです:async function startConversation() {
// 1. 自前サーバーから一時トークンを取得
const response = await fetch('/realtime/token');
const data = await response.json();
const EPHEMERAL_KEY = data.client_secret.value;
// 2. WebRTCの準備
const pc = new RTCPeerConnection();
// AIからの音声が届いたら再生する設定
const audioEl = document.createElement('audio');
audioEl.autoplay = true;
pc.ontrack = (e) => audioEl.srcObject = e.streams[0];
// 自分のマイクを追加
const localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
pc.addTrack(localStream.getTracks()[0]);
// 3. OpenAIとSDP(接続情報)を交換
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const sdpResponse = await fetch("https://api.openai.com/v1/realtime?model=gpt-4o-mini-realtime-preview-2024-12-17", {
method: 'POST',
body: offer.sdp,
headers: {
Authorization: `Bearer ${EPHEMERAL_KEY}`,
'Content-Type': 'application/sdp'
}
});
const answer = { type: 'answer', sdp: await sdpResponse.text() };
await pc.setRemoteDescription(answer);
}3. 検証

結論:AIとの会話が「ツール」から「対話」へ
相槌を打つタイミングや、言葉の詰まり方まで人間らしく感じられます。
まぁ、ChatGPTの音声モードの利用と同じ感覚です。
Laravelなら、ここに「会話履歴の保存」や「ユーザー情報の紐付け」を組み合わせるのも簡単です。
実装によっては大きな可能性を感じます!
感じたこと
STTとTTSの組み合わせより会話はスムーズに行えリアルタイム感があるけど、1分くらいの会話で約10円消費し、なかなかマネタイズが難しそう。。。