For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
メインナビゲーション
Theme

リアルタイム翻訳

発話をリアルタイムで翻訳し、翻訳音声と書き起こしをストリーミングで受け取れます。

リアルタイム翻訳では、元の音声を翻訳専用のセッションにストリーミングすると、話者が話している間に翻訳音声と書き起こしの差分を受け取れます。同時通訳、多言語での通話、放送、会議、授業、ビデオ通話ルームなどに利用できます。

人の発言を翻訳するアプリケーションには gpt-realtime-translate を使用してください。質問に答え、ツールを呼び出しながら会話を進めるアシスタントが必要な場合は、代わりに gpt-realtime-2.1 を標準の Realtime セッションで使用してください。

翻訳セッションと音声エージェントセッションの違い

リアルタイム翻訳セッションと音声エージェントセッションでは、アーキテクチャが異なります。

音声エージェントセッション 翻訳セッション
/v1/realtime に接続します。 /v1/realtime/translations に接続します。
モデルがアシスタントとして動作します。 モデルが通訳者として動作します。
会話と応答のライフサイクルに沿って動作します。 入力音声に応じて翻訳結果を継続的にストリーミングします。
ツールを呼び出したり、アシスタントの発話を生成したりすることがあります。 翻訳音声と書き起こしの差分を生成します。
response.create を呼び出せます。 response.create は呼び出しません。

音声ストリームが届くと翻訳が始まります。フレーズの間の無音も含めて音声を追加し続け、出力イベントは届くたびに処理してください。

通信方式の選択

ブラウザで音声を取得または再生する場合は WebRTC を使用します。WebRTC では、元の音声をメディアトラックとして送信し、翻訳音声をリモートの音声トラックとして受信します。アプリ側で音声をリサンプリングしたり、PCM チャンクを再生したりする必要はありません。

Twilio Media Streams、SIP メディア、放送用の入力ストリーム、メディアワーカーなどを通じて、サーバーがすでに生の音声データを受信している場合は WebSocket を使用します。WebSocket では、24 kHz の PCM16 音声を Base64 でエンコードして送信し、返された音声の差分をアプリ側で再生します。

ブラウザでの 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 と sounddevice、Ruby では async-websocket(gem install async-websocket)をインストールしてください。Java では、Maven の依存関係に com.openai:openai-java:4.75.1 を追加してください。

Java の例では、接続の確立、言語の設定、音声の入力を個別に示します。Java SDK はイベントの受信とセッションの終了にも対応していますが、このガイドにはその手順の Java コード例がないため、Java の例だけでは翻訳の流れ全体を確認できません。以下の手順を最初から最後まで試すには、Node.js または Python の例を使用してください。

翻訳セッションへの接続
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 ブロック内に挿入します。挿入位置は、セッションの作成を確認した後、ブロックが終わる前です。音声の送信中と翻訳イベントの受信中は接続を開いたままにしてください。

Java の接続例では、try ブロックを抜けるとソケットが閉じます。Java の設定例と音声入力例には、開いた状態の TranslationConnection が必要です。音声の送信中と出力の受信中は接続を開いたままにしてください。ブロックを抜ける前にセッションの終了処理を開始し、session.closed を受信するまで残りのイベントをすべて読み取ってください。手順は「WebSocket セッションの終了」を参照してください。

ソケットが開いたら、翻訳先の言語を設定します。

翻訳先の言語の設定
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);
  }
});

Go では、音声の送信と並行して listen を実行します。この関数は session.closed を受信すると接続を閉じます。

WebSocket セッションの終了

元の音声ストリームが終了したら、WebSocket を閉じる前に session.close イベントを送信してください。このイベントを受け取ると、サービスは未処理の入力音声を処理し、残りの翻訳音声と書き起こしをすべて出力してから、session.closed イベントを送信します。session.close イベントは翻訳セッションでのみ使用できます。

session.close を送信した後は音声の追加を止め、通常の受信ループで session.closed を受信するまでイベントを読み取り続けてください。すぐにソケットを閉じると、セッションからの送信が完了していない翻訳結果が失われることがあります。

翻訳セッションの終了
let translationSessionClosing = false;
let gotTranslationClosed = false;
let drainDeadline;

ws.on("close", () => {
  clearTimeout(drainDeadline);
  if (!gotTranslationClosed) {
    console.error("Translation disconnected before final session.closed");
    process.exitCode = 1;
  }
});

function closeTranslationSession() {
  if (translationSessionClosing) {
    return;
  }

  translationSessionClosing = true;
  // Adjust this deadline for your application's finalization requirements.
  drainDeadline = setTimeout(() => {
    console.error("Translation finalization timed out");
    process.exitCode = 1;
    ws.close();
  }, 15_000);
  ws.send(JSON.stringify({ type: "session.close" }));
}

// Use this in place of the earlier output handler, so audio plays only once.
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 === "error") {
    clearTimeout(drainDeadline);
    console.error("Translation error", event.error?.code);
    process.exitCode = 1;
    ws.close();
  }

  if (event.type === "session.closed") {
    clearTimeout(drainDeadline);
    gotTranslationClosed = true;
    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 つ使用します。
  • 必要に応じて、元の言語と翻訳先の言語の両方で書き起こしを表示します。
  • 元の音声、翻訳音声、字幕、ミュート、音量を利用者が操作できるようにします。
  • 再接続中、遅延中、利用不可の各状態を表示します。
  • 遅延は翻訳品質とは別に計測します。

関連ガイド

Realtime と音声の概要

音声エージェント、翻訳、書き起こしの各セッションを比較します。

WebRTC 接続

ブラウザのメディアを Realtime セッションに接続します。

WebSocket 接続

サーバー側のメディアパイプラインを通じて、生の音声データをストリーミングします。

リアルタイム書き起こし

ライブ音声の書き起こしの差分をストリーミングで受け取ります。