For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
기본 탐색 메뉴
Theme

WebSocket

서버에서 관리하는 오디오 스트림을 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 종속성을 설치한 다음 예제를 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 모노 PCM으로, 부호 있는 16비트 샘플을 리틀 엔디언으로 저장합니다. 기본값입니다.
  • {"type":"audio/pcm","rate":16000}: 16 kHz 모노 PCM으로, 부호 있는 16비트 샘플을 리틀 엔디언으로 저장합니다.
  • {"type":"audio/pcmu","rate":8000}: 8 kHz G.711 μ-law이며 샘플당 1바이트입니다.
  • {"type":"audio/pcma","rate":8000}: 8 kHz G.711 A-law이며 샘플당 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를 받기 전에 전송 오류가 발생하거나 시간이 초과되면 최종 사용량을 확인할 수 없습니다. 전체 세션 수명 주기는 세션 관리를 참고하세요.