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을 참고해 주세요.
오디오 길이는 Metadata의 start + duration으로 계산돼요. 멀티채널(multichannel=true&channels=2)의 경우, Metadata.channels 값과 각 Results의 channel_index를 비교해 가장 큰 채널 수로 사용료를 계산합니다. 비용 로그는 call_type: pass_through_endpoint로 표시돼요.
curl -s "http://localhost:4000/spend/logs?api_key=sk-1234" -H "Authorization: Bearer ***"
알려진 제약 사항 (Known Limitations)
/listenWebSocket 스트리밍 엔드포인트만 지원돼요.prompt_tokens,completion_tokens같은 필드는deepgram/<model>비용 산정에 사용되지 않아요.callback,callback_method파라미터는 지원되지 않아요.