AGTCloud API Docs
ガイドAPIリファレンス連携とリソース更新とヘルプ
リアルタイム

GPT-Live リアルタイム音声

GPT-Live WebSocket API を使用して、全二重の音声対話とセッションイベントを処理します。

GPT-Live は、持続的な WebSocket 接続を通じて全二重の音声対話を提供します。1 つのセッション内で、入力音声の送信、音声と文字起こしの受信、セッション設定の更新、複数ターンのコンテキスト維持を行えます。現在このドキュメントで扱うモデルは gpt-live-1 です。実際の利用可否は、現在のアカウントとモデルカタログによって異なります。

WSS
wss://api.agtcloud.cn/v1/live/sessions

認証と接続

サーバーアプリケーションは、WebSocket ハンドシェイク Header で Bearer API キーを使用します。モデルは Query String には含めず、接続後の最初の session.start イベントで設定します。

項目値
接続 URLwss://api.agtcloud.cn/v1/live/sessions
AuthorizationBearer your-api-key
モデルの指定場所session.start.session.model
入力音声Base64 でエンコードした生の PCM 音声チャンク

長期 API キーは、信頼できるサーバーだけに保存してください。このページではこの WebSocket Route のみを扱い、WebRTC、SIP、Sideband 接続、セッション Fork、録音ダウンロードは扱いません。

セッションフロー

  1. Bearer API キーを使用して WebSocket 接続を確立します。
  2. session.start を送信し、モデル、指示、音声、Delegation 方式を設定します。
  3. session.started を受信してから、音声またはアプリケーションコマンドの送信を開始します。
  4. 入力文字起こし、出力文字起こし、出力音声、Usage イベントを継続的に処理します。
  5. 音声の生成が停止したら、session.close を送信します。
  6. その後もイベントを受信し、session.closed の最終 Usage を使用してセッションを終了処理します。

1 回の発話ターンの終了は、セッションの終了ではありません。複数ターンの会話では同じ接続を維持し、アプリケーションがセッション全体を終了する準備ができたときだけ session.close を送信してください。

開始パラメーター

フィールド型説明
typestring最初のフレームでは常に session.start
event_idstringエラーの関連付けに使用する任意のクライアントイベント識別子
session.modelstring必須の GPT-Live モデル ID
session.instructionsstring任意の音声アシスタント向け指示
session.audio.formatobject24 kHz の audio/pcm などの音声形式
session.audio.output.voicestringmarin などの出力 Voice。利用可能な値はモデルによって異なります
session.delegationobjectclient または responses を使用する Delegation 方式

接続開始後は session.update を使用して指示などの変更可能な設定を更新し、session.updated を待って変更を確認します。同じ接続で session.start を再送しないでください。また、Update イベントで最上位の音声モデルを切り替えないでください。

音声の準備と例

以下の例では、Header なし、モノラル、符号付き 16-bit little-endian、24 kHz の PCM 音声を使用します。100 ms ごとのチャンクは 4,800 Byte で、送信前に Base64 でエンコードします。

# 入力音声を準備
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ac 1 -ar 24000 audio.pcm

# 保存した出力音声を再生
ffplay -f s16le -ar 24000 -ac 1 reply.pcm

Node.js の例では ws が必要です。Python の例はセッションの開始と終了のみを確認し、音声は送信しません。

npm install ws
python -m pip install websocket-client
WSSGPT-Live セッション例
import fs from 'node:fs';
import WebSocket from 'ws';

const key = process.env.API_KEY;
const file = process.argv[2];
if (!key || !file) throw new Error('API_KEY と PCM ファイルパスが必要です');

const pcm = fs.readFileSync(file);
if (!pcm.length || pcm.length % 2) {
  throw new Error('PCM は空でない 16-bit サンプル単位のデータである必要があります');
}

const ws = new WebSocket('wss://api.agtcloud.cn/v1/live/sessions', {
  headers: { Authorization: 'Bearer ' + key },
  handshakeTimeout: 10000,
});
const audioOut = fs.createWriteStream('reply.pcm');
let started = false;
let closing = false;
let finalized = false;
let sender;
let drain;
let offset = 0;
let inputFinishedAt = 0;
let lastOutputAt = 0;

function send(event) {
  ws.send(JSON.stringify(event));
}

function closeSession(reason) {
  if (closing) return;
  closing = true;
  clearInterval(sender);
  console.error('リクエストを終了します:', reason);
  if (started && ws.readyState === WebSocket.OPEN) {
    send({ type: 'session.close' });
    drain = setTimeout(() => ws.terminate(), 15000);
  } else {
    ws.terminate();
  }
}

const limit = setTimeout(() => closeSession('60 秒のサンプル上限'), 60000);

ws.on('open', () => send({
  type: 'session.start',
  event_id: 'start_001',
  session: {
    model: 'gpt-live-1',
    instructions: '日本語で簡潔に回答し、ユーザーが先に話すのを待ってください。',
    audio: {
      format: { type: 'audio/pcm', rate: 24000 },
      output: { voice: 'marin' },
    },
    delegation: { type: 'client' },
  },
}));

ws.on('message', (raw) => {
  let event;
  try {
    event = JSON.parse(raw.toString());
  } catch {
    closeSession('無効な JSON');
    return;
  }

  if (event.type !== 'session.output_audio.delta') {
    console.log(raw.toString());
  }
  if (event.type === 'session.started' && !started) {
    started = true;
    sender = setInterval(() => {
      if (closing || ws.readyState !== WebSocket.OPEN) return;
      if (offset >= pcm.length) {
        inputFinishedAt ||= Date.now();
        if (
          lastOutputAt &&
          Date.now() - Math.max(lastOutputAt, inputFinishedAt) >= 3000
        ) {
          closeSession('出力が完了しました');
          return;
        }
        send({
          type: 'session.input_audio.append',
          audio: Buffer.alloc(4800).toString('base64'),
        });
        return;
      }
      const chunk = pcm.subarray(offset, offset + 4800);
      offset += chunk.length;
      send({
        type: 'session.input_audio.append',
        audio: chunk.toString('base64'),
      });
    }, 100);
  }
  if (event.type === 'session.output_audio.delta') {
    lastOutputAt = Date.now();
    audioOut.write(Buffer.from(event.delta, 'base64'));
  }
  if (event.type === 'session.output_transcript.delta') {
    lastOutputAt = Date.now();
  }
  if (event.type === 'session.closed') {
    finalized = true;
    ws.close(1000);
  }
  if (event.type === 'error') closeSession('サービスエラー');
});

ws.on('error', (error) => {
  console.error(error.message);
  closeSession('接続エラー');
});

ws.on('close', (code, reason) => {
  clearTimeout(limit);
  clearTimeout(drain);
  clearInterval(sender);
  audioOut.end();
  console.error({ code, reason: reason.toString(), finalized });
  if (!finalized || code !== 1000) process.exitCode = 1;
});

process.on('SIGINT', () => closeSession('ユーザーによって停止されました'));

イベントリファレンス

この API は、session.input_audio.append で Base64 音声を送信します。Muse の Binary 音声フレームと endStream、OpenAI Realtime の input_audio_buffer.* イベントは使用しません。

クライアントイベント · Session

session.start

モデル、指示、音声、Delegation 設定を指定して GPT-Live セッションを開始します。

フィールド型必須説明例
typestringはい常に `session.start` です。session.start
event_idstringいいえクライアントイベント識別子です。start_001
session.modelstringはいGPT-Live モデル ID です。gpt-live-1
session.instructionsstringいいえ音声アシスタントの会話指示です。日本語で簡潔に回答してください。
session.audio.format.typestringいいえ音声形式の種類です。audio/pcm
session.audio.format.rateintegerいいえ音声のサンプルレートです。24000
session.audio.output.voicestringいいえ出力 Voice です。marin
session.delegation.typestringはいDelegation 方式です。client
JSONの例
{
  "type": "session.start",
  "event_id": "start_001",
  "session": {
    "model": "gpt-live-1",
    "instructions": "日本語で簡潔に回答してください。",
    "audio": {
      "format": {
        "type": "audio/pcm",
        "rate": 24000
      },
      "output": {
        "voice": "marin"
      }
    },
    "delegation": {
      "type": "client"
    }
  }
}

使用量と課金

session.usage.updated は、1 ターン分の増分ではなく、現在のセッションにおける累積使用量を返します。複数段階の値を加算しないでください。通常終了時は、session.closed.usage.seconds を最終的なセッション時間として使用します。

料金には、音声セッション時間、Delegation 先モデルの使用量、ツール呼び出しが含まれる場合があります。現在の料金とモデルの利用可否は、モデルカタログで確認してください。

Delegation 方式

  • client:アプリケーション自身が Delegation されたタスクを処理します。基本的な音声セッションを初めて検証する場合は、この方式を使用します。
  • responses:サーバーが設定された Responses モデルとツールを実行します。対象モデル、ツール、権限は現在のサイトで利用可能である必要があります。

responses では、Delegation 先モデルとツールの使用量に対して追加料金が発生する場合があります。例の MODEL_ID を常に利用できるモデルとして扱わないでください。

エラー処理

症状確認事項
ハンドシェイクが 401 を返すBearer API キー、モデル権限、現在のサイトアドレスを確認します
Path が 404 を返す最終的な接続 Path が /v1/live/sessions であり、/v1 が重複していないことを確認します
最初のフレームでエラーまたは起動タイムアウト接続直後に session.start を送信し、session.started を受信してから音声を送信します
音声がない、または音声が歪むPCM の Bit Depth、Byte Order、サンプルレート、チャンネル数、WAV Header の除去を確認します
session.closed イベントがない最後の累積 Usage、エラーイベント、終了理由を保存し、入力音声全体を自動再送しないでください
Delegation されたタスクが拒否されるResponses モデル、ツール、権限、現在のサイト機能を確認します

参考資料