Deepgram Realtime

Deepgram Realtime (/listen) WebSocket 패스스루

Deepgram의 실시간(realtime) 음성 인식 API(wss://api.deepgram.com/v1/listen)로 라이브 오디오를 스트리밍할 수 있는 WebSocket 패스스루 기능을 소개할게요. LiteLLM 프록시가 호출자를 LiteLLM 가상 키로 인증하고, Deepgram 자격 증명은 서버 측에서 주입해요. 오디오와 전사(transcript) 프레임은 양방향으로 그대로(변경 없이) 중계되며, 소켓이 닫힐 때 해당 세션의 오디오 길이(Metadata.duration)를 비용(모델 deepgram/<model>)으로 기록해요.

출처: 문서

본문

엔드포인트 (Endpoints)

프록시를 통해 다음 WebSocket 엔드포인트로 접속할 수 있어요.

ws://<proxy>/deepgram/v1/listen
ws://<proxy>/deepgram/listen

이 주소들은 내부적으로 <DEEPGRAM_API_BASE>/listen, 즉 wss://api.deepgram.com/v1/listen으로 전달됩니다.

설정 (Configuration)

DEEPGRAM_API_KEY 환경 변수에 Deepgram 키를 설정해요. 프록시 설정(config.yaml)에서 해당 모델에 use_in_pass_through: true를 지정하면 돼요.

export DEEPGRAM_API_KEY="your-deepgram-key"
export LITELLM_MASTER_KEY="sk-1234"
litellm --config config.yaml --port 4000

설정 파일은 다음과 같아요.

model_list:
  - model_name: nova-3
    litellm_params:
      model: deepgram/nova-3
      api_key: os.environ/DEEPGRAM_API_KEY
      use_in_pass_through: true
general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

DEEPGRAM_API_BASE 환경 변수(기본값 https://api.deepgram.com)로 Deepgram 호스트를 바꿀 수도 있어요. https://, http://, wss://, ws:// 모두 지원됩니다.

인증 (Authentication)

호출자 측 인증은 다음 중 하나로 처리돼요.

Authorization: Bearer ***
api-key: ***
Sec-WebSocket-Protocol: openai-insecure-api-key.<litellm-key>

(마지막 방식은 OpenAI 실시간 API 클라이언트 호환용이에요.) 인증 실패 시 HTTP 1011 상태 코드가 반환됩니다.

쿼리 파라미터 (Query Parameters)

URL의 ? 뒤에 붙는 Deepgram 쿼리 파라미터(encoding, sample_rate, channels, language, interim_results, smart_format, punctuate 등)는 그대로 전달돼요. 전체 목록은 Deepgram Listen Streaming 참조를 확인해 주세요. 특히 model 파라미터로 모델을 지정할 수 있어요.

model=nova-3

사용 예시 (Usage)

Python + websockets

import asyncio
import json
import websockets
PROXY_URL = "ws://localhost:4000/deepgram/v1/listen?model=nova-3&encoding=linear16&sample_rate=16000&interim_results=true"
LITELLM_KEY = "sk-1234"
async def main() -> None:
    async with websockets.connect(
        PROXY_URL,
        additional_headers={"Authorization": f"Bearer {LITELLM_KEY}"},
    ) as ws:
        async def send_audio() -> None:
            with open("audio.raw", "rb") as f:  # 16 kHz, 16-bit, mono PCM
                while chunk := f.read(8000):
                    await ws.send(chunk)
                    await asyncio.sleep(0.25)
            await ws.send(json.dumps({"type": "CloseStream"}))
        async def read_frames() -> None:
            async for frame in ws:
                data = json.loads(frame)
                if data.get("type") == "Results":
                    alt = data["channel"]["alternatives"][0]
                    label = "final" if data.get("is_final") else "interim"
                    print(f"[{label}] {alt['transcript']}")
                elif data.get("type") == "Metadata":
                    print(f"[metadata] duration={data['duration']}s")
        await asyncio.gather(send_audio(), read_frames())
asyncio.run(main())

websocat (CLI)

websocat -b \
  -H "Authorization: Bearer ***" \
  "ws://localhost:4000/deepgram/v1/listen?model=nova-3&encoding=linear16&sample_rate=16000" \
  < audio.raw

JavaScript (WebSocket)

const ws = new WebSocket(
  "ws://localhost:4000/deepgram/v1/listen?model=nova-3&encoding=linear16&sample_rate=16000",
  ["openai-insecure-api-key.sk-1234"],
);
ws.onmessage = (event) => console.log(JSON.parse(event.data));
// send Int16 PCM chunks with ws.send(arrayBuffer)

무엇이 전달되고 무엇이 전달되지 않나요? (What is and is not forwarded)

프록시가 생성/소비하는 제어 프레임(KeepAlive, Finalize, CloseStream)은 별도로 처리되고, 클라이언트 인증 헤더(Authorization, api-key)는 제거돼요. 대신 내부적으로 Authorization: Token <DEEPG...KEY> 헤더로 Deepgram에 인증합니다.

응답 측에서 Results(전사 결과)와 UtteranceEnd, SpeechStarted 같은 이벤트는 그대로 중계돼요. 다만 Metadata 프레임은 비용 계산을 위해 내부적으로 소비되므로 클라이언트에 전달되지 않을 수 있어요. 잘못된 요청 시 HTTP 1008 상태 코드가 반환됩니다.

비용 추적 (Cost Tracking)

비용은 Metadata 프레임의 duration(초)과 모델의 input_cost_per_second를 곱해 계산되며, deepgram/<model> 형식(model_prices_and_context_window.json에 정의)으로 기록돼요. 자세한 가격 목록은 model_prices_and_context_window.json을 참고해 주세요.

오디오 길이는 Metadatastart + duration으로 계산돼요. 멀티채널(multichannel=true&channels=2)의 경우, Metadata.channels 값과 각 Resultschannel_index를 비교해 가장 큰 채널 수로 사용료를 계산합니다. 비용 로그는 call_type: pass_through_endpoint로 표시돼요.

curl -s "http://localhost:4000/spend/logs?api_key=sk-1234" -H "Authorization: Bearer ***"

알려진 제약 사항 (Known Limitations)

  • /listen WebSocket 스트리밍 엔드포인트만 지원돼요. prompt_tokens, completion_tokens 같은 필드는 deepgram/<model> 비용 산정에 사용되지 않아요.
  • callback, callback_method 파라미터는 지원되지 않아요.

더 알아보기 (Learn more)