リアルタイム翻訳では、翻訳専用のセッションに元の音声をストリーミング送信し、話者が話している間に翻訳済みの音声と文字起こしの差分を受信できます。リアルタイムの通訳、多言語通話、放送、会議、レッスン、ビデオルームなどに利用できます。
人の発言を翻訳するアプリケーションには、gpt-realtime-translate を使用します。質問への回答、ツールの呼び出し、会話の進行を行うアシスタントが必要な場合は、代わりに標準の Realtime セッションで gpt-realtime-2.1 を使用します。
翻訳セッションと音声エージェントセッションの違い
リアルタイム翻訳セッションは、音声エージェントセッションとは異なるアーキテクチャを使用します。
| 音声エージェントセッション | 翻訳セッション |
|---|---|
/v1/realtime に接続します。 | /v1/realtime/translations に接続します。 |
| モデルがアシスタントとして動作します。 | モデルが通訳として動作します。 |
| 会話と応答のライフサイクルを使用します。 | 入力音声に基づいて継続的にストリーミング出力します。 |
| ツールを呼び出し、アシスタントのターンを生成する場合があります。 | 翻訳済みの音声と文字起こしの差分を生成します。 |
response.create を呼び出せます。 | response.create は呼び出しません。 |
翻訳は音声ストリーム自体をきっかけに始まります。フレーズ間の無音も含めて音声を追加し続け、出力イベントを受信するたびに処理します。
トランスポートの選択
ブラウザで音声を取得または再生する場合は、WebRTC を使用します。WebRTC では、元の音声をメディアトラックとして送信し、翻訳済みの音声をリモート音声トラックとして受信するため、リサンプリングや PCM チャンクの再生を自分で処理する必要はありません。
Twilio Media Streams、SIP メディア、放送の取り込み、メディアワーカーなど、サーバーですでに生の音声を受信している場合は、WebSocket を使用します。WebSocket では、base64 エンコードした 24 kHz PCM16 音声を送信し、返された音声の差分を自分で再生します。
ブラウザでの WebRTC セッションの作成
ブラウザアプリでは、サーバーで有効期間の短いクライアントシークレットを作成します。通常の API キーをブラウザに公開しないでください。
app.post("/session", async (req, res) => {
const language = req.body.targetLanguage ?? "es";
const response = await fetch(
"https://api.openai.com/v1/realtime/translations/client_secrets",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
"OpenAI-Safety-Identifier": "hashed-user-id",
},
body: JSON.stringify({
session: {
model: "gpt-realtime-translate",
audio: {
output: { language },
},
},
}),
}
);
res.status(response.status).json(await response.json());
});ブラウザで音声を取得してピア接続を作成し、翻訳通話用エンドポイントに SDP オファーを POST します。
const { value: clientSecret } = await fetch("/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ targetLanguage: "es" }),
}).then((response) => response.json());
const sourceStream = await navigator.mediaDevices.getUserMedia({
audio: true,
});
const pc = new RTCPeerConnection();
pc.addTrack(sourceStream.getAudioTracks()[0], sourceStream);
const translatedAudio = new Audio();
translatedAudio.autoplay = true;
pc.ontrack = ({ streams }) => {
translatedAudio.srcObject = streams[0];
};
const events = pc.createDataChannel("oai-events");
events.onmessage = ({ data }) => {
const event = JSON.parse(data);
if (event.type === "session.output_transcript.delta") {
subtitles.textContent += event.delta;
}
};
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const sdpResponse = await fetch(
"https://api.openai.com/v1/realtime/translations/calls",
{
method: "POST",
headers: {
Authorization: `Bearer ${clientSecret}`,
"Content-Type": "application/sdp",
},
body: offer.sdp,
}
);
if (!sdpResponse.ok) {
throw new Error(await sdpResponse.text());
}
await pc.setRemoteDescription({
type: "answer",
sdp: await sdpResponse.text(),
});WebSocket セッションの作成
翻訳専用のエンドポイントに接続し、URL でモデルを指定します。
この例を実行する前に、Node.js の場合は ws、Python の場合は websocket-client、Ruby の場合は async-websocket(gem install async-websocket)をインストールしてください。
import WebSocket from "ws";
const ws = new WebSocket(
"wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
{
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
}
);Ruby では、Async::WebSocket::Client.connect ブロック内の、セッションの作成を確認する処理の後、ブロックが終わる前に、以下の構成用と音声追加用のコードスニペットを挿入してください。音声を送信し、翻訳イベントを受信している間は、接続を開いたままにしてください。
ソケットが開いたら、翻訳先の言語を設定します。
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "session.update",
session: {
audio: {
output: {
language: "es",
},
},
},
})
);
});続いて、音声を継続的に追加します。
ws.send(
JSON.stringify({
type: "session.input_audio_buffer.append",
audio: base64Pcm16,
})
);翻訳済みの音声と文字起こしの受信を待ち受けます。
ws.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "session.output_audio.delta") {
playPcm16(event.delta);
}
if (event.type === "session.output_transcript.delta") {
process.stdout.write(event.delta);
}
if (event.type === "session.input_transcript.delta") {
updateSourceTranscript(event.delta);
}
});WebSocket セッションの終了
元のストリームが終了したら、WebSocket を閉じる前に session.close イベントを送信します。このイベントは、保留中の入力音声をすべて処理し、残りの翻訳済み音声と文字起こしを出力してから、session.closed イベントを送信するようサービスに指示します。session.close イベントは翻訳セッションでのみサポートされています。
session.close を送信したら音声の追加を停止し、session.closed を受信するまで通常の受信ループでイベントを読み取り続けます。すぐにソケットを閉じると、セッションからまだ送信中の翻訳出力が失われる可能性があります。
let translationSessionClosing = false;
function closeTranslationSession() {
if (translationSessionClosing) {
return;
}
translationSessionClosing = true;
ws.send(
JSON.stringify({
type: "session.close",
})
);
}
ws.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "session.output_audio.delta") {
playPcm16(event.delta);
}
if (event.type === "session.output_transcript.delta") {
process.stdout.write(event.delta);
}
if (event.type === "session.input_transcript.delta") {
updateSourceTranscript(event.delta);
}
if (event.type === "session.closed") {
ws.close();
}
});
// Call this when the source stream ends.
closeTranslationSession();視聴者向け翻訳の構築
1 人の話者または 1 つのストリームからの音声を翻訳して視聴者に届ける場合は、視聴者向け翻訳を使用します。ライブ配信、カンファレンスでの講演、ウェビナー、決算説明会、講義、動画などがその例です。
一般的なアーキテクチャは次のとおりです。
source audio -> translation session -> translated audio + subtitles
翻訳先の言語ごとに翻訳セッションを 1 つ作成します。同じ英語の音声からスペイン語とフランス語の出力が必要な場合は、英語からスペイン語へのセッションと、英語からフランス語へのセッションを 1 つずつ作成します。
ブラウザの視聴者向け翻訳アプリでは、getDisplayMedia() でタブの音声を取得し、WebRTC で送信して、リモートの翻訳済み音声トラックを再生します。本番環境での放送では、サーバーのメディアワーカーで翻訳を実行し、翻訳済みの音声トラックまたは字幕を視聴者に配信します。
会話翻訳の構築
2 人以上の参加者が異なる言語で会話する場合は、会話翻訳を使用します。サポート通話、営業通話、個別指導、ビデオルームなどがその例です。
参加者の音声トラックは分けておきます。複数の話者の音声を 1 つのストリームに混ぜると、話者の識別、話者ごとの字幕、発話の重なりの処理が難しくなります。
2 人での通話では、翻訳の方向ごとに 1 つの翻訳セッションを作成します。
Caller A audio -> translate into Caller B language -> play to Caller B
Caller B audio -> translate into Caller A language -> play to Caller A
グループルームでは、発話中の話者数と翻訳先の言語によってセッション数が決まります。
translation sessions ~= active source speaker tracks x distinct target languages
小規模なルームでは、各リスナーが、翻訳を聞きたいリモートの話者ごとにブラウザ側で翻訳用のサイドカーを作成できます。大規模なルームでは、サーバー側の参加者またはメディアワーカーを使用します。各話者の元の音声を 1 回だけ購読し、翻訳先の言語ごとに 1 つの翻訳セッションを作成して、翻訳済みの音声トラックを再配信します。
品質と遅延のテスト
実際の音声を使い、両方の言語を理解する人のレビューを通じて翻訳をテストします。自動評価指標は役立ちますが、ユーザーが気づく誤りをすべて検出できるわけではありません。
テストする項目は次のとおりです。
- 言語ペアごとの品質
- 名前、数値、日付、通貨、電話番号
- 分野固有の専門用語
- コードスイッチングと複数の言語が混在する会話
- アクセント、早口、発話の重なり
- 最初の翻訳音声が出力されるまでの遅延
- 発話終了時の遅延
- 字幕の表示タイミング
- 声の一貫性
- 再接続時の動作
名前や専門用語の正確さが重要なユースケースでは、リリース前に正解付きの評価データセットを作成し、失敗例を人の手でレビューします。
本番環境向けチェックリスト
- ブラウザのメディアには WebRTC を、サーバーのメディアには WebSocket を選択します。
- 専用の
/v1/realtime/translationsエンドポイントを使用します。 - フレーズ間の無音も含め、音声を途切れずにストリーミングします。
- WebSocket セッションを閉じる前に、
session.closeを使用し、session.closedを待ちます。 - 会話の翻訳では、話者ごとに音声トラックを分けます。
- 出力言語ごとに 1 つのセッションを使用します。
- 必要に応じて、原文と翻訳文の両方の文字起こしを表示します。
- 元の音声、翻訳音声、字幕、ミュート、音量を操作できるコントロールを用意します。
- 再接続中、遅延中、利用不可の状態を表示します。
- 翻訳品質とは別に遅延を追跡します。
関連ガイド
音声エージェント、翻訳、文字起こしの各セッションを比較します。
ブラウザのメディアをリアルタイムセッションに接続します。
サーバー側のメディアパイプラインを通じて生の音声をストリーミングします。
ライブ音声の文字起こしを差分としてストリーミングします。