# Deep Interview Spec: luke_scribe — 로컬 STT 전사 API 시스템 > 내부용(비공개) 음성/영상 → 텍스트 전사 API. 로컬 모델 실행, GPU/CPU 자동·수동 선택, > 실시간(WebSocket) + 배치(파일/영상), 작업 큐·진행률, 혼용어 대응, 후처리, Colab 자동 노출. ## Metadata - Interview ID: `di-luke-scribe-stt-20260602` - Rounds: 3 (스코어링) + 추가 아이디어 1 + 열린 결정 확정 1 - Final Ambiguity Score: **~10%** (threshold 20%; 열린 결정 6건 확정 후) → **재산출 ~5%** (계획 v2.2 종합 + Open Q 후속확정, 2026-06-07; 상세 §Clarity Re-computation) - Type: **greenfield** (빈 저장소 `luke_scribe`) - Generated: 2026-06-02 - Threshold: 0.2 / Threshold Source: `default` - Initial Context Summarized: no - Status: **PASSED · 결정 확정 완료 · CCG 외부리뷰 반영(v2.2) · Open Q 후속확정·모호도 ~5% 재산출(2026-06-07)** ## Clarity Breakdown | Dimension | Score | Weight | Weighted | |-----------|-------|--------|----------| | Goal Clarity | 0.94 | 0.40 | 0.376 | | Constraint Clarity | 0.90 | 0.30 | 0.270 | | Success Criteria | 0.86 | 0.30 | 0.258 | | **Total Clarity** | | | **0.904** | | **Ambiguity** | | | **0.096 (~10%)** | ## Clarity Re-computation (계획 v2.2 + 후속 결정 종합 · 2026-06-07) > 동일 모델로 재산출. 계획 v2.2가 P0×3/P1×4/P2×3 + 모호 AC 4건을 해소(특히 Success Criteria 수치화: AC-4 entity ≥95%, AC-7 RSS ±15%, OOM ≤2, 429/413, Phase Exit 게이트)했고, 후속 결정(취소=협조적, 모델 단일통일 규칙, HW·동시성=적응형 위임)으로 잔여 분기를 닫음. | Dimension | 기존 | 재산출 | Weight | Weighted | |-----------|------|--------|--------|----------| | Goal Clarity | 0.94 | **0.96** | 0.40 | 0.384 | | Constraint Clarity | 0.90 | **0.95** | 0.30 | 0.285 | | Success Criteria | 0.86 | **0.95** | 0.30 | 0.285 | | **Total Clarity** | 0.904 | | | **0.954** | | **Ambiguity** | 0.096 | | | **0.046 (~5%)** | **잔여 모호(전부 측정/코드 시점에만 닫힘):** ① AC-4 R-WER 기준선(P1 bench), ② 하이브리드→단일 최종 확정(P1 bench 결과), ③ CT2 GIL→실시간 프로세스 분리(P3). → 대화 레버 소진, 다음 레버는 **P1 bench 실행**. --- ## Topology (확정 컴포넌트) | # | Component | Status | 설명 | 커버리지 | |---|-----------|--------|------|----------| | 1 | **Ingestion API** | active | 실시간 스트림(WebSocket) + 파일/영상 업로드 수집 | AC-1, AC-7, AC-9 | | 2 | **Transcription Engine** | active | 로컬 STT(faster-whisper), **하이브리드: 실시간=turbo / 배치=large-v3** | AC-4 | | 3 | **Realtime Pipeline** | active | VAD·청크·부분/최종 결과 스트리밍 | AC-8 | | 4 | **Output / Results** | active | 요청별 출력옵션(txt/ts/word/diarize/SRT/VTT), 결과 보관(7일) | AC-9, AC-11 | | 5 | **Job Queue / Concurrency** (1급) | active | Job 추상화, **Redis 영속 큐**, 워커풀, 우선순위 레인, queue_position·진행률 | AC-5, AC-6 | | 6 | **Device Manager** (횡단) | active | GPU/CPU 자동감지 → 정밀도·워커수·동시성 자동 산정, 강제 플래그 | AC-2, AC-3 | | 7 | **Post-processing** | active | glossary/rules + (옵션)LLM 보정(백엔드 설정화) + confidence 플래그 | AC-10 | | 8 | **Connectivity / Tunnel** | active | Colab 등 공인 IP 없는 환경 자동 외부 노출(cloudflared 등) | AC-13 | --- ## Goal **내부 서비스가 호출하는 비공개 API로, 실시간 음성·녹음 파일·mp3·mp4(및 기타 영상)를 입력받아 로컬에서 실행되는 STT 모델로 텍스트로 전사한다.** 실시간 입력은 준실시간(3~5초 내 부분 결과)으로 전사한다. 모델은 감지된 하드웨어(GPU/CPU)에 맞춰 정밀도·동시성을 자동 결정하되 `auto | cpu | cuda` 강제 선택도 가능하다. 다수 작업을 동시/대기열로 처리하고, 호출자는 대기열 위치와 진행률을 조회할 수 있다. 한국어 중심이되 한·영 혼용 기술용어(예: "API", "vLLM")를 음차로 망가뜨리지 않고 정확히 전사한다. **정확도가 중요한 배치는 large-v3, 저지연이 중요한 실시간은 turbo**로 분리한다(하이브리드). --- ## Constraints (제약) - **로컬 실행(STT).** 외부 STT API(구글/AWS 등) 의존 금지 — Whisper를 우리 하드웨어에서 직접 실행. 모델 가중치는 **미존재 시 HuggingFace에서 자동 다운로드(인터넷 OK), 손상 시 재다운로드**. *에어갭/오프라인 강제는 요구사항 아님.* - **하드웨어 폭이 매우 넓음:** 개발=GTX 1050(Pascal, 2~4GB), 테스트=Colab/T4/L4/A100/H100. → 고정 수치 설정 불가, **자동 산정 필수**. - **정밀도 자동 선택:** compute capability ≥ 7.0 → fp16, Pascal(6.x) → int8, VRAM 부족 → CPU 폴백, CPU → int8. - **동시성/워커 수는 감지된 VRAM·코어로 자동 산정**(오버라이드만 허용). - **모델 하이브리드:** 실시간=turbo, 배치=large-v3 (둘 다 설치, `model` 오버라이드 가능). - **언어:** 한국어 우선 + 자동 감지, 한·영 혼용(code-switching) 정확도가 하드 요구. - **실시간 전송:** WebSocket. 목표 지연 3~5초(관대) → 정확도 우선 청킹 가능. - **인증:** API Key 헤더(내부용). - **큐:** **Redis 영속 큐(RQ, no-fork)** — 재시작 내성·다중 워커. **Colab/개발은 in-process 폴백(Redis 불필요)**. - **보관:** 결과/메타만 **7일** 보관(설정화·자동삭제), **업로드 원본 오디오는 처리 후 즉시 삭제**. - **파일 상한:** 모든 입력 **비동기 Job 기본**, 절대 상한 **4시간 / 2GB**(초과 `413`, 설정화). - **배포 이원화:** CLI(셸 스크립트)=개발·테스트·Colab / Docker(FastAPI/Python)=프로덕션(내부). - **CPU 폴백은 항상 지원.** ## Non-Goals (명시적 비범위) - 외부 공개(public) API·과금·멀티테넌시 SaaS 기능. - 자체 STT 모델 학습/파인튜닝(기성 Whisper 계열 사용). - 번역(translation) — 1차 범위 외. - 프런트엔드 UI(API/CLI만 제공). - 영구 원본 오디오 아카이빙(원본은 삭제가 기본). --- ## Acceptance Criteria (검증 가능 기준) - [ ] **AC-1** 동일 시스템으로 파일(오디오/영상)·실시간(WebSocket) 입력을 모두 전사한다. - [ ] **AC-2** `device=auto`가 GTX 1050에서 int8/CPU로, T4/L4/A100/H100에서 fp16로 자동 동작하고, `cpu`/`cuda[:n]` 강제 플래그가 동작한다. - [ ] **AC-3** 정밀도·워커 수가 감지된 VRAM/compute capability로 자동 산정되며 `--workers`/`--compute-type` 오버라이드가 가능하다. - [ ] **AC-4** 혼용어 검증: *"그 API 서빙할 때 vLLM 쓰면 성능 대박이야"* 입력 시 "API", "vLLM"이 영문 그대로(핫워드 적용 시) 전사된다. 배치 경로(large-v3)에서 정확도가 더 높음을 확인한다. - [ ] **AC-5** 동시 다중 작업을 받아 Redis 큐에 적재/동시 처리하며, 작업 중에도 신규 입력을 계속 수신한다. - [ ] **AC-6** 호출자가 `queue_position`(앞 N건)과 `progress`(처리된 길이/전체, %)를 조회할 수 있다. - [ ] **AC-7** 장시간/대용량 파일이 VAD 세그먼트로 분할되어 진행률을 제공하고 메모리 사용이 일정하다. 4h/2GB 초과는 `413`. - [ ] **AC-8** 실시간 부분 결과가 3~5초 내 스트리밍되고 최종 결과로 안정화된다(turbo 경로). - [ ] **AC-9** 영상 파일이 ffmpeg로 오디오 추출 후 전사되고, 출력 옵션(timestamps/word/diarize/formats)이 요청별로 동작한다. - [ ] **AC-10** 후처리: glossary/rules가 동작하고, LLM 보정(백엔드 `local`/`external` 설정화, 기본 off·신뢰도 게이팅)과 저신뢰 구간 플래그가 동작한다. - [ ] **AC-11** API Key 인증이 적용되고, 전사 완료 후 원본 오디오가 삭제되며 결과만 7일 보관된다. - [ ] **AC-12** CLI(`serve`/`transcribe`/`bench`/`detect`)와 Docker(GPU/CPU 이미지 + Redis)로 각각 실행된다. - [ ] **AC-13** Colab에서 `--tunnel cloudflare`로 공개 URL이 자동 발급되어 외부에서 호출된다. --- ## Architecture (상세 설계) ### 시스템 개요도 ``` ┌───────────────────────────────────────────────┐ 내부 호출자 │ luke_scribe API │ (서비스/CLI) │ │ │ │ ┌──────────────┐ ┌────────────────────┐ │ REST ├──── 파일/영상 ─▶│ │ Ingestion API│────▶│ Job Queue (Redis) │ │ (HTTP)│ │ │ (FastAPI) │ │ - priority lanes │ │ │ │ │ - upload │ │ (realtime/batch) │ │ WS ├── 실시간 오디오▶│ │ - WS stream │ │ - queue_position │ │ │ │ │ - auth(API │ │ - progress │ │ │ │ │ Key) │ │ - durable/재시작내성 │ │ │ │ └──────┬───────┘ └─────────┬──────────┘ │ │ │ │ ffmpeg(영상→오디오) │ dispatch │ │ │ ▼ ▼ │ │ │ ┌──────────────┐ ┌────────────────────┐ │ │ │ │ Realtime │ │ Worker Pool │ │ │ │ │ Pipeline │ │ (N = 자동산정) │ │ │ │ │ VAD→chunk→ │◀───▶│ ┌───────────────┐ │ │ │ │ │ partial/final│ │ │ Engine │ │ │ │ │ │ (turbo) │ │ │ faster-whisper│ │ │ │ │ └──────┬───────┘ │ │ rt=turbo │ │ │ │ │ │ │ │ batch=large-v3│ │ │ │ │ ▼ │ └──────┬────────┘ │ │ │ │ ┌──────────────┐ │ │ │ │ │ │ │Post-processing│◀───┤ │ uses │ │ │ │ │glossary/rules │ └─────────┼───────────┘ │ │ │ │+LLM(opt,plug) │ │ │ │ │ │+conf flag │ ┌─────────▼──────────┐ │ │ │ └──────┬───────┘ │ Device Manager │ │ │ │ ▼ │ GPU/CPU 감지 → │ │ │◀── 결과/진행률 ─┤ ┌──────────────┐ │ fp16·int8·CPU / │ │ │ (txt/srt/ │ │Output/Results│ │ worker수·동시성 │ │ │ vtt/json) │ │store(7일,결과)│ └────────────────────┘ │ │ │ └──────────────┘ │ │ │ Connectivity/Tunnel (Colab→cloudflared 자동) │ │ └───────────────────────────────────────────────┘ ``` ### 1) Ingestion API (입력/수집) **REST (배치/파일):** | Method | Path | 설명 | |--------|------|------| | `POST` | `/v1/jobs` | multipart: `file`(오디오/영상) + `options`(JSON). → `{job_id, status:"queued", queue_position}` | | `GET` | `/v1/jobs/{id}` | 상태 조회: `queued`(queue_position, jobs_ahead) / `processing`(progress %, processed_sec/total_sec, eta) / `completed` / `failed`(error) | | `GET` | `/v1/jobs/{id}/result?format=txt\|srt\|vtt\|json` | 결과 조회(포맷 변환) | | `DELETE` | `/v1/jobs/{id}` | 작업 취소 | | `GET` | `/v1/jobs` | 작업 목록/필터 | **WebSocket (실시간):** `WS /v1/stream` - 1) **init 프레임(첫 메시지=인증):** `{type:"init", api_key, audio:{codec,sample_rate,channels}, options:{language:"ko", ...}}` — 2초 내 유효 init 없으면 close. *브라우저는 WS 핸드셰이크에 헤더를 못 넣으므로 인증은 이 첫 메시지로.* - 2) 클라이언트 → 오디오 청크(PCM16/opus 등) 연속 전송 - 3) 서버 → `{type:"partial", text, t0,t1}`(가설) / `{type:"final", segment, start, end, words[]}`(확정) / `{type:"status", ...}` **Admin/관측:** `GET /health`, `GET /v1/system`(device 프로파일·워커수·큐 깊이), `GET /v1/models`. **인증:** REST = `X-API-Key` 헤더. **WS = 첫 `init` 메시지의 `api_key`**(헤더 못 쓰는 브라우저 대응; 키가 URL/로그에 안 남음). 키별 스코프/사용량 확장 여지. **요청 옵션 스키마(`options`):** ```jsonc { "language": "ko", // 기본 ko(한국어 우선). "auto"|"en"|"ja"... 요청별 override "model": null, // null=경로별 기본(rt=turbo, batch=large-v3). 오버라이드 가능 "device": "auto", // "auto" | "cpu" | "cuda" | "cuda:0" "compute_type": null, // null=자동. "float16"|"int8"|"int8_float16" "timestamps": true, // 세그먼트 타임스탬프 "word_timestamps": false, // 단어 단위 "diarize": false, // 화자 분리(pyannote, opt, HF 토큰) "formats": ["json"], // ["txt","srt","vtt","json"] "hotwords": [], // (선택) 반복되는 고정 도메인 용어만 1회 등록. 미예측 — 비우면 ko+모델+후처리로 대응 "glossary_id": null, // 저장된 도메인 사전 참조 "vad": true, // 무음 제거 "post_correction": { // 단계 제어 "mode": "rules", // "none"|"glossary"|"rules"|"llm" "backend": "local", // llm 모드 시: "local"|"openai"|"external" "corrector_model": null // 백엔드별 모델/엔드포인트 } } ``` ### 2) Transcription Engine (전사 엔진) - **런타임:** **faster-whisper (CTranslate2)** — openai-whisper 대비 ~4배 빠르고 메모리 적음, GPU/CPU·fp16/int8 지원, Silero VAD 내장, 배치 추론 지원. - **모델 전략(확정): 하이브리드** - **실시간 경로 = large-v3-turbo** (저지연; 디코더 4층 경량화). - **배치 경로 = large-v3** (혼용어/다국어 정확도 우위). - 두 모델 모두 설치, 경로별 기본값 적용. `model` 옵션/환경변수로 런타임 오버라이드. - **혼용어 대응(핵심):** 1. `hotwords`/`initial_prompt`에 도메인 용어 주입 → 기술용어 음차화 방지. 2. 저장 가능한 **Glossary**(도메인 사전) → `glossary_id`로 재사용. 3. (옵션) 후처리 LLM 보정으로 잔여 오류 교정. - **제외:** distil-whisper, NVIDIA Parakeet/Canary(영어 중심 → 한국어 혼용 부적합). > ✅ **결정 근거:** 다국어/혼용어 정확도는 **large-v3가 turbo보다 우위**(turbo는 일부 언어 정확도 하락). 따라서 정확도 중요한 배치는 large-v3, 저지연 중요한 실시간은 turbo로 분리(하이브리드 확정). 추후 도메인 샘플 WER 벤치로 실시간 경로의 v3 승격 여부 재평가 가능. ### 3) Realtime Pipeline (실시간) - WebSocket 오디오 프레임 → 링버퍼 → **Silero VAD**로 발화 구간 검출 → 청크 구성 → 전사 → 부분/최종 방출. - **안정화 정책:** LocalAgreement(연속 가설 일치분 확정) 또는 AlignAtt(2025 SOTA). 지연이 3~5초로 관대하므로 **큰 청크 + LocalAgreement-2**로 정확도 우선. 실시간 경로 기본 모델은 **turbo**. - **참고 구현:** [WhisperLive](https://github.com/collabora/WhisperLive)(faster-whisper 백엔드, WS, VAD), [WhisperLiveKit](https://github.com/QuentinFuxa/WhisperLiveKit)(AlignAtt), [whisper_streaming](https://github.com/ufal/whisper_streaming)(→ SimulStreaming 대체 추세). 정책 채택/재구현 모두 가능. ### 4) Output / Results (출력·보관) - 텍스트 기본 + 요청 옵션별 타임스탬프/단어/화자/자막. - 포맷 변환: `json`(원천) → `txt`/`srt`/`vtt`/structured-`json`. - **보관(확정):** 결과/메타만 **7일** 보관(설정화·만료 자동삭제), **원본 오디오는 전사 직후 삭제**. - 저장소: 기본 로컬 파일/SQLite, 확장 시 S3/DB 가능. ### 5) Job Queue / Concurrency (큐·동시성) - **Job 추상화:** 파일·실시간·영상 모두 Job으로 통일. 작업 중에도 신규 Job 계속 수신. - **우선순위 레인:** 실시간 세션=저지연 우선 / 배치=처리량 레인. - **워커풀:** 워커 수 = Device Manager 자동 산정. 각 워커가 디바이스 바인딩된 모델 인스턴스 보유. - **큐 백엔드(확정):** **Redis + RQ(no-fork)** 영속 큐를 처음부터 사용 → 재시작 내성·다중 워커 프로세스 지원. *Celery 기본 prefork는 CUDA와 충돌하므로 no-fork 워커 사용.* (Colab/개발용 in-process 폴백.) - **진행률:** 장시간 파일은 VAD 세그먼트 분할 → `progress = 완료 세그먼트 / 전체`(또는 처리 오디오초/전체초). `queue_position` = 큐 인덱스. - **백프레셔:** 최대 큐 길이 초과 시 `429`. ### 6) Device Manager (능력 등급 자동판정 — 설계 중심축) **감지:** GPU 유무·device name·compute capability·**VRAM(총/여유)**, **시스템 RAM**, **디스크 여유**(모델 다운로드 공간). **능력 등급(Capability Tier) 자동판정:** 부팅 시 실측으로 *어떤 모델을 어디서 어떻게* 제공할지 결정 — **무음 모델 강등이 아니라, 등급이 "제공 가능 모델"을 정함.** | 등급 | 하드웨어가 감당하는 것 | 동작 | |---|---|---| | **T0 · CPU** | GPU로 turbo도 무리(또는 GPU 없음) | turbo를 **CPU**로 실행 | | **T1 · turbo-GPU** | turbo는 GPU OK, large-v3는 무리 | turbo만 GPU. **large-v3 미제공**(배치도 turbo) | | **T2 · 스왑** | large-v3는 되지만 turbo와 **동시 상주**는 무리 | 호출에 따라 모델 **로드/언로드**(한 번에 하나 상주, MRU 유지로 스왑 최소화) | | **T3 · 동시상주** | turbo + large-v3 **동시 적재** 가능 | 둘 다 상주 → 실시간(turbo)+배치(large-v3) **동시 처리** | | ~~T4 · 다중복제~~ | 모델 여러 벌 병렬 적재 | **제외**(복잡도 과다) | - **정밀도:** cc≥7.0 → fp16/int8_float16, Pascal(6.x, 예 1050) → int8, CPU → int8. (부팅 VRAM 실측으로 확정.) - **모델 적재 가능성은 부팅 실측으로 판정**(정적 상수 비의존): turbo 미적재→CPU(T0), large-v3 미적재→미제공(T1), 동시 미적재→스왑(T2), 동시 적재 가능→동시상주(T3). - **디스크 가드:** turbo ~1.6GB / large-v3 ~3GB 다운로드 전 여유 공간 점검, 부족 시 명확 오류. - **투명성:** `/v1/system`·`/v1/models`로 현재 **등급·제공 가능 모델**, 결과엔 **`model_used`/`compute_type_used`** 항상 표시 → 몰래 강등 없음. - **오버라이드:** `--device auto|cpu|cuda:N`, `--compute-type`, `--model`, `--workers`. - **CLI `detect`**로 등급·제공모델·권장설정 출력. **1050**: 보통 T1(turbo-int8)/T0. **T4~H100**: T3 하이브리드 풀가동. ### 7) Post-processing (전사 오류 후처리) 순차 파이프라인(요청별 `post_correction.mode`로 단계 제어): 1. **Glossary/Hotwords (선택):** 반복되는 고정 도메인 용어를 1회 등록해 디코드 바이어스. *매 전사 예측이 아님* — 안 쓰면 ko 앵커+모델+규칙으로 대응. 2. **Rule/Dictionary 정규화(deterministic):** 알려진 오인식 → 표준 용어 치환, 정규식, 약어 대소문자 보정. 3. **LLM 보정(확정: 백엔드 설정화, 기본 off·confidence-gated):** 저신뢰/고WER 구간만 교정(Judge-Editor: 고신뢰 스팬 유지, 불확실 스팬만 재작성). **백엔드 플러그형** — `local`(소형 LLM, 오프라인·프라이버시) 또는 `openai`/`external`(OpenAI 호환 엔드포인트), `corrector_model` 설정 가능. 기본 비활성(약 HW 보호·과교정 방지). 4. **Confidence 플래깅:** 세그먼트별 신뢰도 부여, 저신뢰 구간 표시 → 선택적 휴먼 리뷰. > ⚠️ **리서치 근거:** LLM 후처리는 **입력 WER이 높을 때(>10%)** WER을 크게 낮추지만, 이미 정확한 전사에는 **paraphrastic drift(과교정)** 위험 → 신뢰도 게이팅 필수. 도메인 고유명사/기술용어 손상이 핵심 위험(R-WER/EWER로 측정). > 🔒 **프라이버시:** `external`/`openai` 백엔드는 전사 텍스트를 외부로 전송하므로 내부 전용 정책과 상충 가능 → **기본은 `local`**, 외부 백엔드는 명시적 opt-in. ### 8) Connectivity / Tunnel (Colab 자동 외부 노출) - **환경 자동 감지**(Colab/Kaggle/dev) → 옵션 시 터널 기동. - **기본: cloudflared Quick Tunnel** — `https://.trycloudflare.com`, **계정/도메인 불필요**, 임시 URL, 제로 설정. (`--tunnel cloudflare`) - **대안: ngrok** — authtoken 필요, 무료는 재시작 시 URL 변경, 요청 인스펙션 제공. (`--tunnel ngrok --ngrok-token ...`) - **안정 도메인:** named Cloudflare Tunnel(CF 계정+도메인 필요). - **프로덕션/실IP:** `--tunnel none`, host IP 바인딩. - 기동 시 공개 URL + API Key 출력. ### 배포 (Deployment) — 코드는 하나, 실행 프로파일 둘 | | **Colab / 개발** | **프로덕션(내부)** | |---|---|---| | 실행 | **순수 Python / `run.sh`로 python 직접** (Docker ❌) | Docker + `docker-compose` | | 큐 | **in-proc(Redis 불필요)** | Redis + 별도 worker | | 저장 | 로컬 디스크 1개(공유 이슈 없음) | **공유 볼륨/오브젝트 스토어**(api↔worker) | | 가중치 | 받아서 캐시(예: Drive) | 받아서 캐시(미존재 시 다운로드) | | 외부노출 | **cloudflared 바이너리** 실행 | 실제 IP | - **CLI (`run.sh` + `cli.py`)**: `serve`(API+옵션 터널) / `transcribe ` / `bench`(모델·등급 벤치) / `detect`(등급·프로파일). **Colab은 Docker 불가 → 반드시 이 경로.** - **Docker(프로덕션)**: GPU 이미지(`nvidia/cuda`) + CPU(slim). compose: API + **Redis** + worker(+옵션 LLM). **입력 원본·파생 wav·결과는 공유 스토어**(컨테이너 경계에서 안 깨지게). - **모델 프로비저닝(공통):** 시작 시 존재 확인 → 없으면 다운로드 → 손상(로드 실패/체크섬) 시 재다운로드 → 준비 전엔 `status:"loading"`. - **설정:** env+`.env`/yaml — model(rt/batch), device, workers, api_keys+scopes, retention_days, tunnel, redis_url(프로덕션), corrector+allowlist. ### 기술 스택 (제안) Python 3.11+, **FastAPI** + uvicorn, **faster-whisper(CTranslate2)** (turbo + large-v3), **ffmpeg**(영상→16kHz mono), **Silero VAD**(faster-whisper 내장), **Redis + RQ(no-fork)**(영속 큐), pydantic v2, **LLM 보정 백엔드**(local: llama.cpp/transformers · external: OpenAI 호환 client), (옵션) **pyannote.audio**(diarization, HF 토큰), **cloudflared**/pyngrok(터널), loguru/structlog(로깅), prometheus-client(메트릭, 옵션). --- ## Assumptions Exposed & Resolved (가정 노출·해소) | Assumption | Challenge | Resolution | |------------|-----------|------------| | "한 번에 한 작업이면 충분" | 동시/대기 다작업·중간 추가 입력은? | 큐를 1급 승격, Redis 영속, 우선순위 레인 + queue_position/progress | | "엔진은 정하면 끝" | 혼용어 vs 속도 충돌 | **하이브리드**(실시간 turbo / 배치 large-v3) + 핫워드/후처리 | | "동시성 수치를 정해야 함" | 1050~H100 폭이 너무 큼 | Device Manager가 VRAM/CC로 정밀도·워커수 자동 산정 | | "출력 형식을 시스템이 고정" | 호출마다 다를 수 있음 | 요청 `options`로 출력 옵션 전달(요청별) | | "실시간은 최저 지연 필수" | 3~5초도 허용 | 큰 청크 + 안정화 정책으로 정확도 우선 | | "Colab도 IP로 호출" | Colab은 공인 IP 없음 | cloudflared Quick Tunnel 자동 노출 | | "전사 결과만 보면 됨" | 오인식/오타 교정은? | 후처리 파이프라인(glossary→rules→LLM(opt, 백엔드 설정화)→flag) | | "후처리는 로컬만" | 외부 LLM 허용? | local/external 백엔드 설정화, external은 프라이버시 opt-in | --- ## Ontology (Key Entities) | Entity | Type | Fields | Relationships | |--------|------|--------|---------------| | Job | core | id, type(file/stream/video), status, queue_position, progress, options, created_at | has many Segment, produces TranscriptResult | | AudioInput | core | source(stream/file/video), codec, duration, size | belongs to Job | | Engine | core | runtime(faster-whisper), model(turbo/large-v3), compute_type | used by Worker | | Device | core | kind(gpu/cpu), name, vram_total/free, compute_capability | profiled by DeviceManager | | DeviceProfile | supporting | precision, max_workers, fallback | derived from Device | | Worker | core | id, device, model_instance, busy | consumes Queue(Redis), runs Engine | | Queue | core | lane(realtime/batch), depth, backend(redis) | holds Job | | Segment | supporting | index, start, end, text, words[], confidence | belongs to Job | | TranscriptResult | core | text, segments[], formats, language | belongs to Job | | RequestOptions | supporting | language, model, device, formats, hotwords, post_correction | configures Job | | Glossary | supporting | id, terms[] | applied to Engine/Post-processing | | PostProcessor | supporting | mode, backend(local/external), corrector_model, stages | transforms TranscriptResult | | Session(realtime) | core | ws_conn, buffer, options | produces partial/final Segment | | ApiKey | supporting | key, scopes, usage | authorizes Job | | RetentionPolicy | supporting | result_ttl=7d, delete_source=true | governs Output | | Tunnel | supporting | provider(cloudflare/ngrok/none), public_url | exposes API | ## Ontology Convergence | Round | Entity Count | New | Changed | Stable | Stability Ratio | |-------|-------------|-----|---------|--------|----------------| | 1 | 10 | 10 | - | - | N/A | | 2 | 13 | 3 | 0 | 10 | ~77% | | 3 | 14 | 1 | 0 | 13 | ~92% | | 추가반영 | 16 | 2 (PostProcessor, Tunnel) | 0 | 14 | ~88% | | 결정확정 | 16 | 0 | 1 (Queue→Redis) | 16 | ~100% (수렴) | --- ## 확정된 결정 (Resolved Decisions) | # | 결정 | 확정 내용 | |---|------|-----------| | 1 | 모델 전략 | **하이브리드** — 실시간=turbo(저지연), 배치=large-v3(혼용어 정확도). 모델 설정 오버라이드 가능. | | 2 | 큐 영속성 | **Redis 영속 큐(RQ, no-fork)** 처음부터 — 재시작 내성·다중 워커. Colab/개발 in-process 폴백. | | 3 | LLM 후처리 | 포함, **백엔드 설정화**(local 소형 LLM / OpenAI 호환 external), 기본 off·confidence-gated. external은 프라이버시 opt-in. | | 4 | 결과 보관 | **7일**(설정화·자동삭제). 원본 오디오는 전사 직후 삭제. | | 5 | 파일 상한 | 모든 입력 **비동기 Job 기본**, 절대 상한 **4시간 / 2GB**(초과 `413`, 설정화). | | 6 | 화자 분리 | **옵션 포함**(pyannote, HF 토큰), 기본 off, 요청 시 `diarize=true`. | | 7 | 취소 의미론 | **협조적 취소(세그먼트 경계)로 충분** 확정. hard-kill 비채택(필요 시 follow-up). *(2026-06-07)* | | 8 | 모델 단순화 규칙 | P1 bench에서 turbo entity **≥95%(+R-WER≤기준선) 시 배치도 turbo 단일모델로 통일**(기본 지향=단순화). 미달 시 하이브리드 유지. *(2026-06-07)* | | 9 | 배포HW·동시성 | **단일 타깃 미고정** → §6 하드웨어 적응형 자동산정에 위임. WS 동시 N도 자동산정(고정 목표 없음). *(2026-06-07)* | --- ## CCG 외부 리뷰 반영 (v2.2) 외부 advisor(Codex/Gemini) 리뷰 + 사용자 확정으로 갱신: - **모델 프로비저닝:** 인터넷 다운로드 OK(에어갭 아님). 미존재→다운로드, 손상→재다운로드, 로딩 중 `status:"loading"`. (구 "오프라인 동작" 문구 폐기.) - **능력 등급 자동판정(§6):** GPU VRAM·RAM·디스크로 **T0(CPU)~T3(turbo+large-v3 동시상주)** 자동 결정, T4(다중복제) 제외. 결과에 **`model_used`** 항상 표시(무음 강등 없음). - **기본 언어 `ko`** + 요청별 override. **hotwords는 선택**(매 전사 예측 아님). - **WS 인증 = 첫 `init` 메시지**(api_key+오디오포맷+옵션). - **배포 2프로파일:** Colab/개발=순수 Python·in-proc·바이너리 cloudflared / 프로덕션=Docker+Redis+공유 스토어. - (미채택·추후 검토: webhook 콜백, Idempotency-Key, 목록 페이지네이션, 만료 결과 `410`.) --- ## 구현 로드맵 (제안 Phase) | Phase | 범위 | 산출 | |-------|------|------| | **P1 Core** | faster-whisper 통합(turbo+large-v3), Device Manager 자동감지, CLI `transcribe`/`detect`, 파일 동기 전사, ffmpeg 영상 추출 | 단발 전사 동작(1050/CPU 포함) | | **P2 API+Queue** | FastAPI, **Redis 영속 큐**·워커풀, 상태/진행률 API, API Key, 결과 보관(7일)·원본 삭제, Docker(GPU/CPU/Redis) | 비동기 배치 API | | **P3 Realtime** | WebSocket 스트리밍, VAD 청크, LocalAgreement 부분/최종(turbo) | 실시간 전사 | | **P4 Output+Post** | timestamps/word/SRT/VTT, glossary/rules 후처리, confidence flags | 풍부한 출력 + 1차 후처리 | | **P5 Advanced** | LLM 후처리 백엔드(local/external, 옵션), diarization(pyannote, 옵션), Colab cloudflared 자동, 메트릭/모니터링, `bench` | 운영·고급 기능 | ## 리스크 - **약 GPU(1050) 실시간 한계:** turbo도 Pascal/2GB에선 버거움 → int8/CPU 폴백, 실시간은 사실상 T4+ 권장(문서화). - **turbo 혼용어 정확도:** 핫워드/후처리로 보완하되 도메인 벤치로 검증, 필요 시 실시간도 v3 승격. - **LLM 후처리 과교정:** 신뢰도 게이팅 필수. - **외부 LLM 후처리 프라이버시:** `external`/`openai` 백엔드 사용 시 전사 텍스트 외부 전송 → 내부 전용 정책 검토 필요(기본 local). - **Redis 의존성:** 영속 큐가 Redis에 의존 → 단일 장애점. HA/단발용 in-process 폴백으로 완화. - **GPU 메모리 동시성:** 워커당 VRAM 추정 오차 → 보수적 산정 + OOM 재시도/강등. - **Quick Tunnel 임시 URL:** trycloudflare는 비영구 → 안정 필요 시 named tunnel/ngrok. --- ## Interview Transcript (요약)
Q&A (3 라운드 + 추가 아이디어 + 결정 확정) **Round 0 — Topology:** 4개 컴포넌트 + 큐/동시성·중간 추가입력·대기열 위치·진행률·대용량 처리 요구 → 큐 1급 승격. **Round 1 (100%→~40%)** - 엔진: 혼용어 대응 + 속도 중요, 후보 large-v3, 추천 요청. - 언어: 한국어+자동감지, 혼용어("vLLM 쓰면 성능 대박") 정확 전사 필수. - 실시간 전송: **WebSocket**. **Round 2 (~40%→~26%)** - 엔진: turbo 단일(속도) → 이후 하이브리드로 확정. - 하드웨어: GTX 1050·Colab·T4/L4/A100/H100 → **자동 감지·자동 용량 산정**. - 동시성: **하드웨어 기반 자동 조절**. - 출력: **요청별 옵션**. **Round 3 (~26%→~14%, PASSED)** - 배포: **CLI + Docker/FastAPI**. 인증: **API Key**. 보관: **결과만·원본 삭제**. 실시간 지연: **3~5초 관대**. **추가 아이디어 (반영)** - 전사 오류 **후처리** → Post-processing(glossary→rules→LLM(opt)→flag). - Colab 등 공인 IP 부재 환경 **자동 외부 노출** → cloudflared Quick Tunnel 기본. **열린 결정 확정 (~14%→~10%)** - 모델=하이브리드, 큐=Redis 영속, LLM 후처리=백엔드 설정화(local/external), 보관 7일, 상한 4h/2GB, 화자분리 옵션(off).
--- *Generated by deep-interview · threshold 20% (default) · ambiguity ~10% (열린 결정 6건 확정) · PASSED*