Speech to Text Streaming API
Streaming API는 WebSocket으로 오디오 chunk를 보내고 transcript delta와 완료 이벤트를 받습니다. 이벤트 이름은 OpenAI Realtime transcription core와 호환되는 형태를 사용하지만 연결 경로는 Kitsch 전용입니다.
연결 정보
wss://api.kitschlabs.com/v1/speech-to-text/stream
서버 환경에서 WebSocket handshake에 아래 인증 헤더 중 하나를 포함하세요.
Authorization: Bearer <API_KEY>
xi-api-key도 사용할 수 있습니다. 일반 브라우저 WebSocket API는 임의의 인증
헤더를 설정할 수 없으므로 API 키를 브라우저에 넣지 말고 서버에서 연결하세요.
연결이 승인되면 서버가 먼저 session.created를 보냅니다.
Session 설정
오디오를 보내기 전에 session.update를 한 번 보낼 수 있습니다.
{
"type": "session.update",
"session": {
"type": "transcription",
"audio": {
"input": {
"format": {"type": "audio/pcm", "rate": 24000},
"transcription": {
"model": "kitsch-stt-v1",
"language": "ko",
"prompt": "Kitsch Labs"
},
"turn_detection": {"type": "server_vad"}
}
}
}
}
서버는 적용된 설정을 session.updated로 반환합니다. 첫 audio chunk를 보낸 뒤에는
session을 변경할 수 없습니다.
지원 오디오 형식
| 형식 | 입력 조건 |
|---|---|
audio/pcm | 24 kHz, mono, signed 16-bit little-endian PCM |
audio/pcmu | 8 kHz, mono, G.711 μ-law |
audio/pcma | 8 kHz, mono, G.711 A-law |
기본값은 audio/pcm, 24 kHz입니다.
오디오를 어떻게 보내나요?
각 chunk를 base64로 인코딩해 보냅니다. 디코딩된 chunk 하나의 최대 크기는 256 KiB입니다.
{
"type": "input_audio_buffer.append",
"audio": "BASE64_AUDIO"
}
기본 server_vad는 발화 종료를 자동으로 감지합니다. 직접 발화를 끝내려면
turn_detection을 null로 설정하고 다음 event를 보냅니다.
{"type":"input_audio_buffer.commit"}
어떤 이벤트를 받나요?
| 이벤트 | 설명 |
|---|---|
session.created | 연결과 transcription session 생성 완료 |
session.updated | session 설정 반영 완료 |
input_audio_buffer.committed | 하나의 발화 입력이 확정됨 |
conversation.item.input_audio_transcription.delta | 확정된 transcript 조각 |
conversation.item.input_audio_transcription.completed | 발화의 전체 transcript와 사용량 |
error | 요청 또는 처리 오류 |
Delta event 예시:
{
"type": "conversation.item.input_audio_transcription.delta",
"event_id": "event_...",
"item_id": "item_...",
"content_index": 0,
"delta": "안녕하세요"
}
완료 event 예시:
{
"type": "conversation.item.input_audio_transcription.completed",
"event_id": "event_...",
"item_id": "item_...",
"content_index": 0,
"transcript": "안녕하세요.",
"usage": {"type": "duration", "seconds": 1.25}
}
item_id와 content_index를 기준으로 delta를 순서대로 이어 붙이고, completed
event의 transcript를 해당 발화의 최종 결과로 사용하세요.
연결 예제
다음 예제는 24 kHz mono signed 16-bit little-endian raw PCM 파일을 보냅니다.
import asyncio
import base64
import json
import os
from websockets.asyncio.client import connect
async def transcribe() -> None:
headers = {"Authorization": f"Bearer {os.environ['KITSCH_API_KEY']}"}
async with connect(
"wss://api.kitschlabs.com/v1/speech-to-text/stream",
additional_headers=headers,
) as websocket:
print(await websocket.recv()) # session.created
await websocket.send(json.dumps({
"type": "session.update",
"session": {
"type": "transcription",
"audio": {
"input": {
"format": {"type": "audio/pcm", "rate": 24000},
"transcription": {"model": "kitsch-stt-v1", "language": "ko"},
"turn_detection": None,
}
},
},
}))
with open("speech.pcm", "rb") as audio:
while chunk := audio.read(64 * 1024):
await websocket.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": base64.b64encode(chunk).decode("ascii"),
}))
await websocket.send(json.dumps({"type": "input_audio_buffer.commit"}))
async for raw_event in websocket:
event = json.loads(raw_event)
if event["type"] == "conversation.item.input_audio_transcription.delta":
print(event["delta"], end="", flush=True)
elif event["type"] == "conversation.item.input_audio_transcription.completed":
print()
break
elif event["type"] == "error":
raise RuntimeError(event["error"]["message"])
asyncio.run(transcribe())
제한과 과금
- 연결 하나의 최대 session 길이는 30초입니다.
- 성공한 연결 시간은 시작된 1초 단위로 올림해 초당 0.1크레딧을 계산합니다.
- 한 연결에서 여러 발화를 처리할 수 있지만 30초 전에 새 session으로 연결하는 것이 좋습니다.
- 일시적인 연결 오류 뒤에는 새 session으로 다시 연결하세요. 이전 session의 audio를 자동으로 재전송하지 마세요.
오류 처리
지원하지 않는 event나 잘못된 설정은 연결을 유지한 채 error event로 반환될 수
있습니다.
{
"type": "error",
"event_id": "event_...",
"error": {
"type": "invalid_request_error",
"code": "invalid_audio",
"message": "The audio field must be valid base64.",
"param": null,
"event_id": "<REQUEST_ID>"
}
}
| Close code | 의미 | 권장 행동 |
|---|---|---|
1000 | 정상 완료 또는 session 제한 도달 | 필요한 경우 새 session 연결 |
1008 | 인증·권한·요청 정책 오류 | 키, credit, 요청 설정 확인 |
1011 | 일시적인 처리 오류 | 제한적으로 재연결 |
1013 | 동시 처리 용량 초과 | backoff 후 재연결 |