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

WebSockets

サーバーが管理する音声ストリームを WebSocket 経由で接続します。

使用する API を選択すると、接続手順とセッションイベントを確認できます。

サーバーから GPT-Live への接続

サーバー間連携を含め、GPT-Live の音声接続には WebRTC を推奨します。

WebSocket も利用できます。メインの WebSocket 接続で音声と JSON イベントを双方向に送受信します。プロジェクトの API キーは信頼できるサーバーで保管してください。

このガイドでは、GPT-Live に音声をストリーミングする方法を説明します。既存のセッションを監視または制御する方法については、サーバー側の制御を参照してください。推論とツール実行を担うバックエンドを Responses API に接続する方法については、Responses の WebSocket モードを参照してください。

認証とセッションの開始

  1. wss://api.openai.com/v1/live/sessions にクエリパラメータを付けずに接続します。Authorization: Bearer $OPENAI_API_KEY で認証し、接続時には例に示すヘッダーを含めます。
  2. 最初のメッセージとして session.start を送信します。モデル、会話の指示、音声形式、音声の種類、委任の設定を session オブジェクト内に指定します。
  3. session.started を受信してから、音声やアプリケーションのコマンドを送信します。このイベントには、確定したセッション設定とセッション ID が含まれます。

以下の例では、音声に Marin、音声形式に 24 kHz の PCM16、バックエンドにウェブ検索を利用できる Responses を使用します。会話の指示は簡潔にしてください。バックエンドの指示、ツール、ツールの権限は、委任とツールに沿って設定してください。

SDK を使った音声ストリーミング

Node.js では、openai と ws を npm install openai ws でインストールし、JavaScript の例を client.mjs として保存します。macOS または Linux で Python を使う場合は、openai[realtime] をインストールし、Python の例を client.py として保存します。サーバーの環境変数に OPENAI_API_KEY を設定してください。これらの例には、Live に対応したバージョンの SDK が必要です。サンプルは標準入力から 24 kHz のモノラル PCM16 の生音声データを読み取り、返された音声を同じ形式で標準出力に書き込みます。入力ストリームをアプリケーションの録音処理に、出力ストリームを再生処理に接続してください。音声ストリームにログや文字起こしイベントが混入しないよう、これらは標準エラー出力に書き出されます。

Go では、Go 1.26 以降を使用します。例を main.go として保存し、go mod init live-demo でモジュールを初期化してから、github.com/openai/openai-go/v3@v3.85.1 を go get でインストールします。Java では、Java 17 以降を使用し、Maven の依存関係に com.openai:openai-java:4.95.0 を追加して、LiveConnectionWebsocketExample クラスを使用します。Ruby 3.3 以降では、gem install openai -v 0.110.0 で SDK を、gem install async-websocket で WebSocket 接続に必要な gem をインストールし、例を client.rb として保存します。

import OpenAI from "openai";
import { LiveWS } from "openai/resources/live/ws";

// stdin and stdout carry raw mono PCM16 audio at 24 kHz, not WAV files.
// Supply microphone bytes continuously and play stdout in the same format.
process.stdin.pause();
const ws = new LiveWS(new OpenAI());
let started = false;
let closing = false;
let finalized = false;
let pendingByte = Buffer.alloc(0);

let closeTimeout;

ws.socket.on("open", () => {
  ws.send({
    type: "session.start",
    event_id: "event_start",
    session: {
      model: "gpt-live-1",
      instructions:
        "Be concise. Delegate requests needing current information to the backend, which can search the web.",
      audio: {
        format: { type: "audio/pcm", rate: 24000 },
        output: { voice: "marin" },
      },
      delegation: {
        type: "responses",
        responses: {
          model: "gpt-5.6-luna",
          tools: [{ type: "web_search" }],
          tool_choice: "auto",
        },
      },
    },
  });
});

process.stdin.on("data", (chunk) => {
  if (!started || closing || ws.socket.readyState !== 1) return;
  const bytes = Buffer.concat([pendingByte, chunk]);
  const completeLength = bytes.length - (bytes.length % 2);
  pendingByte = bytes.subarray(completeLength);
  if (completeLength) {
    ws.send({
      type: "session.input_audio.append",
      audio: bytes.subarray(0, completeLength).toString("base64"),
    });
  }
});

// Register the final-event handler before any close command can be sent.
ws.on("event", (event) => {
  if (event.type === "session.started") {
    started = true;
    console.error("Session ready", event.session.id);
    process.stdin.resume();
  } else if (event.type === "session.output_audio.delta") {
    process.stdout.write(Buffer.from(event.delta, "base64"));
  } else if (event.type === "session.closed") {
    finalized = true;
    clearTimeout(closeTimeout);
    process.stdin.pause();
    console.error("Final session usage", event.usage);
    ws.close();
  } else {
    // Includes transcript deltas and nested response.event usage.
    console.error(JSON.stringify(event));
  }
});

process.on("SIGINT", () => {
  if (closing) return;
  if (!started || ws.socket.readyState !== 1) {
    ws.socket.platformSocket.terminate();
    return;
  }
  closing = true;
  process.stdin.pause();
  ws.send({ type: "session.close" });
  closeTimeout = setTimeout(() => {
    console.error("Incomplete finalization: session.closed was not received");
    process.exitCode = 1;
    ws.socket.platformSocket.terminate();
  }, 15_000);
});
ws.on("error", (error) => {
  console.error(error.message);
  process.exitCode = 1;
});
ws.socket.on("close", () => {
  clearTimeout(closeTimeout);
  process.stdin.pause();
  if (!finalized) {
    console.error("Connection closed without final session usage");
    process.exitCode = 1;
  }
});

音声入力とプレーヤーを接続した状態で、node client.mjs、python client.py、go run .、ruby client.rb、または Java アプリケーションを実行します。Session ready が表示されたら、録音時のサンプルレートに合わせたペースでマイクの音声を連続して入力します。ファイル全体をパイプで一度に渡しても、マイクからのリアルタイム入力は再現できません。音声入力が EOF に達しても会話は終了しません。正常終了を要求するには、プロセスに SIGINT を送信します。

この例では音声ストリームを接続します。録音、バッファリング、再生、必要に応じたリサンプリングはアプリケーション側で行います。モデルの動作を評価する前に、使用するデバイスとネットワークでこれらの処理をテストしてください。

音声形式の選択

起動時に session.audio.format を設定します。入力と出力には同じ形式が適用され、セッション中は変更できません。

  • {"type":"audio/pcm","rate":24000}:24 kHz のモノラル符号付き 16 ビットリトルエンディアン PCM(デフォルト)
  • {"type":"audio/pcm","rate":16000}:16 kHz のモノラル符号付き 16 ビットリトルエンディアン PCM
  • {"type":"audio/pcmu","rate":8000}:8 kHz の G.711 μ-law(1 サンプルあたり 1 バイト)
  • {"type":"audio/pcma","rate":8000}:8 kHz の G.711 A-law(1 サンプルあたり 1 バイト)

WAV などのコンテナヘッダーを含めず、生のバイト列を Base64 でエンコードします。PCM チャンクには完全な 16 ビットサンプルを格納する必要があるため、各チャンクのバイト数は偶数でなければなりません。この例では、末尾に 1 バイト余った場合は次の入力チャンクに繰り越します。それ以外は任意の位置でチャンクを区切れます。ストリームの連続性とデータの順序を保ってください。

音声のサンプルレートが設定値と異なる場合は、リサンプリングしてください。形式の設定を変更しても、入力のバイト列は変換されません。この例を G.711 に対応させるには、PCM 用の 2 バイト境界にそろえる処理を省き、各チャンクの符号化済みバイト列をそのまま転送します。出力プレーヤーにも同じコーデックを設定してください。設定に合った G.711 ストリームは、PCM に変換せずそのまま転送できます。電話回線からの通話を接続する方法については、電話システムとの連携を参照してください。

イベントの送受信

各イベントは JSON テキストメッセージとして送信します。音声は Base64 でエンコードしてメッセージに含めます。

  • 音声の送信: session.input_audio.append を送信する際に、audio に Base64 でエンコードした生のバイト列を指定します。音声の追加に対する確認応答はありません。
  • 音声の受信: delta を各 session.output_audio.delta イベントから取り出してデコードし、設定した形式で順番に再生できるよう音声をキューに追加します。
  • 文字起こしの受信: delta に含まれるテキストを session.input_transcript.delta と session.output_transcript.delta から取得し、それぞれ対応する文字起こしに追記します。
  • バックエンドイベントの受信: Responses に処理を委任する場合は、event を各 response.event エンベロープから取り出して処理します。
  • エラー処理: error イベントを受け取ったら、コマンドの拒否やセッションエラーに対処します。error.client_event_id がある場合は、その値で対象のコマンドを特定します。

再生状況はアプリケーションの音声キューで追跡します。GPT-Live のメインの WebSocket 接続で送られる出力音声にはタイミングを示すフィールドがなく、音声出力の完了を示すイベントもありません。字幕のタイミングを合わせるには文字起こしのタイムスタンプを、委任した処理の進行状況を追跡するにはバックエンドイベントを使用してください。

音声が連続して流れる間、GPT-Live が聞き取りと発話のタイミングを制御します。バックエンドに委任した処理を開始または続行するには、response.create を使用します。手順については、委任とツールを参照してください。

進行中のセッションの設定

Live モデル、会話の初期指示、音声形式、音声の種類、委任モードは起動時に確定し、その後は変更できません。現在の委任モードで変更できる設定は session.update で更新します。省略した設定は現在の値を保持します。更新に成功すると、session.updated が返され、確定したセッション設定を確認できます。

会話の指示を追加するには session.instructions.append を、入力音声を制御するには session.input_audio.mute または session.input_audio.unmute を使用します。入力をミュートしても、バックエンドの処理はキャンセルされず、生成された音声の出力も停止しません。コンテキストの更新、文字起こし、入力の制御、使用量については、セッションの管理を参照してください。

セッションの終了

会話が終わったら session.close を送信します。送信前に session.closed のリスナーを登録し、このイベントが届くまで受信を続けてから接続を解放してください。この例では最大 15 秒待機し、終了イベントが届かなかった場合は、終了処理が完了しなかったことを報告します。

session.closed に含まれる最終的な音声使用量と、受信済みのバックエンドの使用量イベントを保存してください。音声の利用時間は、更新のたびにその時点での累計値が通知されるため、各値を合算しないでください。session.closed を受信する前に通信障害やタイムアウトが発生した場合、最終的な使用量は確認できません。ライフサイクル全体については、セッションの管理を参照してください。