OVERVIEW GPU 음성 인식 개요

OpenAI Whisper large-v3 기반 STT(Speech-to-Text) API입니다. WAV, MP3, M4A, OGG, FLAC 형식의 오디오를 전사(transcript)로 변환합니다. 언어 힌트 지정 또는 자동 감지, 타임스탬프 세그먼트 포함 조회가 가능합니다. 대용량 오디오는 Multipart 모드로 전송해 base64 오버헤드를 제거할 수 있습니다.

Systran/faster-whisper-large-v3 — OpenAI Whisper large-v3를 CTranslate2로 최적화한 고속 음성 인식 모델. 원본 대비 4배 빠르면서 동일한 정확도를 유지합니다. 100개 이상의 언어를 지원하며, 한국어·영어·중국어·일본어에서 우수한 인식률을 보입니다. VAD(Voice Activity Detection)로 무음 구간을 자동 건너뛰어 처리 속도를 향상시킵니다. FP16 VRAM ~3GB.

⚠ STT 태스크 활성화 필요

다른 태스크와 함께 실행하면 VRAM 부족이 발생합니다. 반드시 STT만 단독으로 활성화하세요.

# .env
REDGX_GPU_RELAY_ENABLED=true
REDGX_GPU_STT_ENABLED=true
# 나머지는 false
아키텍처 흐름
# 1. POST → 202 Accepted (request_id 반환)
POST /api/v1/ns/{ns}/gpu/stt
  Content-Type: multipart/form-data  또는 application/json (audio_b64)202 { "request_id": "stt-1710000000000-a1b2c3d4" }

# 2. GET 폴링 → 완료 시 200
GET /api/v1/ns/{ns}/gpu/stt/{request_id}
  → 202 { "status": "queued" }
  → 200 { "status": "completed", "transcript": "..." }

# 데이터 흐름
Client → POST /gpu/stt (오디오 bytes) → Redis Queue → STTWorker
  → Whisper large-v3 → transcript → Redis Outbox → Client
지원 포맷 및 모델 정보
항목
STT 엔진OpenAI Whisper large-v3 (transformers 구현)
모델 선정RTX 3060 12GB 채택 — ~3GB VRAM, 99개 언어 지원
float16 (GPU), float32 (CPU fallback)
지원 포맷 WAV MP3 M4A OGG FLAC (magic bytes 검증)
최대 파일 크기100 MB
오디오 처리openai-whisper load_audio() → 16kHz float32 (ffmpeg 기반)
전송 모드JSON: audio_b64 (base64) / Multipart: file 파트 (권장, base64 오버헤드 없음)
캐시SHA-256(모델명 + 오디오 bytes) — 동일 오디오 GPU 우회
캐시 TTL24시간 (86400초)
폴링 권장 간격2초 (오디오 길이에 따라 가변)
POST 오디오 업로드 · 기본 전사

오디오 파일을 업로드하고 전사 결과를 조회합니다. Multipart 모드(권장)와 JSON Base64 모드 두 가지를 지원합니다. 아래 샘플 파일을 클릭하거나 직접 파일을 드래그하세요.

POST /api/v1/ns/{ns}/gpu/stt
샘플 파일 바로 테스트: 아래 버튼으로 fixtures 폴더의 오디오를 바로 요청할 수 있습니다.
🎧
파일을 드래그하거나 클릭하여 선택
WAV · MP3 · M4A · OGG · FLAC · 최대 100 MB
▶ 미리 듣기 파일을 선택하거나 샘플을 클릭하세요
curl 명령 보기

            
POST 언어 힌트 vs 자동 감지

language 파라미터로 입력 언어를 지정하면 감지 오류를 방지하고 정확도가 향상됩니다. 생략 시 Whisper가 자동으로 언어를 감지하며, 응답의 language 필드에 감지 결과가 반환됩니다.

언어 힌트 지정 vs 자동 감지 비교
언어 코드: Whisper는 ISO 639-1 코드를 사용합니다 (ko, en, ja, zh, fr, de …).
단일 언어 오디오의 경우 힌트를 지정하면 정확도와 속도가 모두 향상됩니다.
▶ 미리 듣기 샘플 파일을 선택하세요
curl 명령 보기

            
POST 세그먼트 · 타임스탬프 조회

include_segments=true를 설정하면 전사 결과와 함께 구간별 타임스탬프를 반환합니다. 자막 생성, 특정 구간 검색 등에 활용할 수 있습니다.

include_segments=true — 타임스탬프 포함 전사
응답 구조: segments[] 배열의 각 항목에 id, start (초), end (초), text 포함.
▶ 미리 듣기 샘플 파일을 선택하세요
curl 명령 보기

            
POST 결과 캐시 테스트

동일한 오디오 파일을 두 번 전송하면 두 번째는 GPU 추론 없이 즉시 반환됩니다. 캐시 키는 SHA-256(모델명 + 오디오 bytes)로 계산됩니다.

캐시 키: SHA-256(모델명 + 오디오 raw bytes) — 동일 파일이라도 다른 language 힌트를 주면 캐시 미스입니다 (캐시는 bytes 기반, language는 캐시 키 제외).
1회차 → 2회차 캐시 적중 확인
▶ 미리 듣기 샘플 파일을 선택하세요
curl 명령 보기

            
MANAGE 결과 관리 — 조회 / 삭제 / 취소

결과는 outbox에 1시간(3600초) 보관됩니다.

GET 결과 조회
curl 명령 보기

            
DELETE 결과 삭제
curl 명령 보기

            
POST 요청 취소
큐 대기 중인 요청만 취소 가능. 처리 중이면 409 반환.
curl 명령 보기

            
POST 배치 상태 일괄 조회

여러 request_id 상태를 한 번의 API 호출로 조회합니다.

POST /gpu/stt/batch-status
curl 명령 보기

            
ERROR 에러 케이스

STT 전용 에러(INVALID_AUDIO_FORMAT)를 포함한 다양한 오류 상황을 테스트합니다.

REF API 레퍼런스
POST /api/v1/ns/{ns}/gpu/stt — 요청 파라미터
Dual Transfer Mode:
JSON 모드 (Content-Type: application/json): audio_b64 필드에 Base64 인코딩 오디오
Multipart 모드 (Content-Type: multipart/form-data): file 파트에 원본 오디오 bytes (권장 — base64 오버헤드 없음)
필드타입기본값설명
audio_b64string (JSON)필수Base64 인코딩 오디오 데이터 (JSON 모드)
filebinary (Multipart)필수오디오 파일 원본 bytes (Multipart 모드)
languagestring | nullnull (자동 감지)입력 언어 힌트 (ko, en, ja …). 지정 시 정확도 향상
modelstring | null서버 기본값Whisper 모델명 (null = 서버 설정값)
include_segmentsboolfalse타임스탬프 세그먼트 목록 반환 여부
POST 202 Accepted 응답
{
  "ok": true,
  "data": {
    "request_id": "stt-1710567890123-a1b2c3d4",
    "task_type":  "stt",
    "hint":       "text_recommended"   // 4KB 미만 업로드 시에만 포함 — JSON 모드 권장 힌트
  }
}

hint 필드는 multipart 업로드가 4KB 미만일 때만 응답에 포함됩니다 (요청은 거부되지 않음). 작은 페이로드에는 base64 JSON 모드가 효율적입니다.

GET 완료 응답 구조 (HTTP 200)
// include_segments=false (기본)
{
  "ok": true,
  "data": {
    "request_id":       "stt-1710567890123-a1b2c3d4",
    "status":           "completed",
    "transcript":       "Ask not what your country can do for you...",
    "language":         "en",           // 감지된 언어
    "duration_seconds": 13.82,          // 오디오 길이
    "segments":         null,           // include_segments=false 시 null
    "model":            "Systran/faster-whisper-large-v3",
    "cached":           false,
    "elapsed_ms":      2350.0
  }
}

// include_segments=true
{
  "data": {
    "transcript": "Ask not what your country...",
    "segments": [
      { "id": 0, "start": 0.0, "end": 3.5, "text": "Ask not what your country", "confidence": null },
      { "id": 1, "start": 3.5, "end": 6.2, "text": "can do for you", "confidence": null },
      ...
    ]
  }
}
필드설명
request_id요청 ID
statuscompleted 또는 failed
transcript전체 전사 텍스트
language감지(또는 지정)된 언어 코드
duration_seconds오디오 길이 (초)
segments타임스탬프 세그먼트 배열 (include_segments=false 시 null)
model실제 사용된 Whisper 모델명
cached캐시 적중 여부
elapsed_ms전체 처리 시간 (ms)
curl 예시
# Multipart 모드 (권장 — 대용량 오디오)
curl -X POST https://localhost:1443/api/v1/ns/HRM/gpu/stt \
  -k \
  -H "X-API-Key: <your-key>" \
  -F "[email protected]" \
  -F "language=ko" \
  -F "include_segments=true"

# JSON 모드 (소용량)
curl -X POST https://localhost:1443/api/v1/ns/HRM/gpu/stt \
  -k \
  -H "X-API-Key: <your-key>" \
  -H "Content-Type: application/json" \
  -d '{"audio_b64":"'"$(base64 -w0 audio.mp3)"'","language":"en"}'

# 결과 조회 (폴링)
curl https://localhost:1443/api/v1/ns/HRM/gpu/stt/stt-xxx -k \
  -H "X-API-Key: <your-key>"

# 결과 조회 후 자동 삭제
curl "https://localhost:1443/api/v1/ns/HRM/gpu/stt/stt-xxx?auto_clear=true" \
  -k -H "X-API-Key: <your-key>"
에러 코드
코드HTTP설명
INVALID_AUDIO_FORMAT400지원하지 않는 오디오 포맷 (magic bytes 검증 실패)
MISSING_AUDIO400JSON 모드: audio_b64 필드 누락 또는 빈 값
MISSING_FILE400Multipart 모드: file 파트 누락
EMPTY_FILE400업로드 파일이 빈 바이트 (multipart 또는 base64 디코딩 결과 0 byte)
INVALID_MULTIPART400multipart/form-data 파싱 실패
INVALID_JSON400JSON 본문 파싱 실패
INVALID_BASE64400audio_b64가 유효한 base64가 아님
UNAUTHORIZED401API Key 누락 또는 잘못됨
NAMESPACE_DENIED403Namespace 접근 권한 없음
GPU_NOT_FOUND404Request ID 없음 또는 만료 (TTL 3600s)
GPU_PAYLOAD_TOO_LARGE413오디오 파일 크기 초과 (max_file_size_mb, 기본 100 MB)
GPU_TASK_DISABLED503STT 태스크 비활성 (REDGX_GPU_STT_ENABLED=false)
GPU_UNAVAILABLE503CUDA 불가 또는 Whisper 모델 로드 실패
GPU_QUEUE_FULL503큐 용량 초과
GPU_PROCESSING409취소 불가 — 이미 처리 중
WS /api/v1/ns/{ns}/gpu/stt/{req_id}/wait — 결과 Push 대기

Redis Pub/Sub으로 완료 알림을 수신 후 즉시 인식 결과를 전송합니다. STT는 오디오 길이에 따라 처리 시간이 길어지므로 폴링보다 이 방식이 적합합니다.

// 인증: Sec-WebSocket-Protocol 헤더로 API 키 전달 (URL 쿼리 미지원)
// 브라우저: new WebSocket(url, ["redgx_ak_hrm_..."])
wss://<host>/api/v1/ns/HRM/gpu/stt/stt-xxx/wait?timeout=120          // 장시간 오디오는 최대 120s 권장
// 완료 — REST GET과 동일 구조
{ "ok": true, "data": { "request_id": "stt-...", "status": "completed",
    "transcript": "인식된 텍스트 전체", "language": "ko",
    "duration_seconds": 13.82, "segments": null,
    "model": "Systran/faster-whisper-large-v3", "cached": false, "elapsed_ms": 1850.0 } }

// 실패
{ "ok": true, "data": { "request_id": "stt-...", "status": "failed", "error": {...} } }

// 인증 실패 → HTTP 403 (upgrade 거부, accept 전 — 4001 close 프레임 미전송)
// Not Found    → { "ok": false, "error": { "code": "GPU_NOT_FOUND" } } + close(4004)
// Timeout      → { "ok": false, "error": { "code": "GPU_TIMEOUT" } }  + close(4008)