Files
luke_scribe/README.md
T
lukehemmin 7327145d7a feat: implement full-platform STT API (v2.3 consensus plan)
Batch+realtime transcription API: faster-whisper engine w/ EngineOwner
(single GPU owner, OOM downgrade chain, persisted attempted_profiles),
hardware-adaptive device manager (T0-T3 VRAM tiers), Redis/in-proc job
queue w/ leases + crash recovery, postprocess (glossary/rules/LLM w/
egress guard), privacy-first result store (UUID keys, source deleted
after transcribe), retention sweeper, API-key auth (HMAC digests,
scopes, job ownership), WebSocket realtime lane (LocalAgreement),
CLI (detect/transcribe/bench/serve/key), Docker, benchmark runner.

127 mock-based tests pass; ruff clean. Includes verification checklist
and autoplan review notes.
2026-08-12 16:01:21 +09:00

117 lines
4.4 KiB
Markdown

# luke_scribe
내부용 **로컬 STT 전사 API** — faster-whisper(CTranslate2) 기반, 하드웨어 적응형, privacy-first.
한국어 + 영문 기술용어(KO+EN code-switching)를 외부 STT API에 보내지 않고
통제된 환경에서 전사한다. 단일 `Job` 추상화로 배치(파일)와 실시간(WebSocket)을 처리한다.
> 설계 단일 진실원본(SoT): [`.omc/plans/consensus-luke-scribe-stt-api.md`](.omc/plans/consensus-luke-scribe-stt-api.md),
> [`.omc/specs/deep-interview-luke-scribe-stt-api.md`](.omc/specs/deep-interview-luke-scribe-stt-api.md)
## 상태
- 설계 완료(모호도 ~5%) · **구현 완료(v0.1 전체 플랫폼, mock 검증)**`feat/full-platform`
- 이 저장소 환경은 CPU-only이고 ffmpeg/모델 다운로드가 없으므로 **단위/통합 테스트는
mock 기반**으로 검증한다. 실제 GPU/모델 스모크는 GPU가 있는 환경에서 수행한다.
## 빠른 시작 (개발)
```bash
# 1) 의존성 (Python 3.11+)
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[engine,api]" # 또는: uv sync --extra engine --extra api
# 2) 환경 설정
cp .env.example .env
# 3) 하드웨어 감지 → 능력 등급/정밀도/워커수
luke-scribe detect
# 4) 단일 파일 전사 (CPU에서도 동작)
luke-scribe transcribe samples/hello-ko-en.wav --language ko --device cpu
# 5) API 서버 (개발 기본: in-proc 큐, Redis 불필요)
luke-scribe serve
# 6) API 키 생성 (1회만 출력, 다이제스트만 저장)
luke-scribe key --create --scopes transcribe,admin
```
### 5분 스모크 (mock 환경에서도 CLI 동작 확인)
```bash
./run.sh test # 단위/통합 테스트
luke-scribe detect # JSON 프로필
```
## CLI
| 명령 | 설명 | 상태 |
|------|------|------|
| `detect` | 하드웨어 감지 · 능력 등급(T0~T3) · 정밀도 · 워커수 | ✅ |
| `transcribe <file>` | 단발 파일 전사 (faster-whisper, CPU/GPU) | ✅ |
| `bench <manifest>` | turbo vs large-v3 도메인 벤치 · 모델 결정 게이트 | ✅ |
| `serve` | FastAPI 서버 (in-proc 또는 Redis 큐) | ✅ |
| `key --create` | API 키 생성 (1회 출력 + 다이제스트 저장) | ✅ |
Exit codes: `0` 성공 · `2` 입력 오류 · `3` 모델/장치 오류 · `4` 추론 오류 · `5` 결과 쓰기 오류 · `130` 인터럽트
## REST API (배치)
| 메서드 | 경로 | 설명 |
|--------|------|------|
| `POST` | `/v1/jobs` | multipart 업로드 (`file` + `options` JSON) → `202 {job_id}` |
| `GET` | `/v1/jobs/{id}` | 상태 · `queue_position` · `progress` |
| `GET` | `/v1/jobs/{id}/result?format=json\|txt\|srt\|vtt` | 결과 |
| `DELETE` | `/v1/jobs/{id}` | 협조적 취소 |
| `GET` | `/v1/jobs` | 내 job 목록 |
| `GET` | `/health` | 헬스체크 (공개) |
| `GET` | `/v1/system` · `/v1/models` | admin 전용 |
인증: `X-API-Key` 헤더 (또는 `Authorization: Bearer`). 스코프 + **Job 소유권** 강제.
```bash
KEY=$(luke-scribe key --create --scopes transcribe | python -c "import sys,json;print(json.load(sys.stdin)['key'])")
curl -X POST localhost:8000/v1/jobs \
-H "X-API-Key: $KEY" \
-F file=@samples/hello-ko-en.wav \
-F 'options={"language":"ko","formats":["json","srt"]}'
```
## WebSocket (실시간)
`WS /v1/stream` — 첫 메시지는 init 프레임(인증 + 오디오 협상):
```json
{"type":"init","api_key":"...","audio":{"codec":"pcm_s16le","sample_rate":16000,"channels":1},"options":{"language":"ko"}}
```
응답: `partial`(가설) / `final`(확정, LocalAgreement) / `status`.
## 벤치마크
```bash
luke-scribe bench benchmarks/manifest.yaml --output benchmarks/report.json --decision benchmarks/decisions/default-model-v1.json
```
절대 기준: entity 보존 ≥95% · K-CER ≤15% · 실패율 0%. 게이트는 turbo 우선,
미달 시 large-v3 채택. 단일 모델 run은 decision artifact를 생성하지 않는다.
## Docker (프로덕션)
```bash
# CPU 프로파일
docker compose --profile cpu up -d
# GPU 프로파일 (NVIDIA Container Toolkit 필요)
docker compose --profile gpu up -d
```
API + Redis + 워커, 공유 스토어 볼륨. `LUKESCRIBE_API_KEYS` 필수.
## 알려진 제한 (v0.1)
- 실시간 decode는 `EngineOwner` 스텁 (실제 WS decode는 GPU 환경에서 활성화).
- Redis/RQ 브로커는 Redis 설치 시에만 동작 (기본 in-proc).
- 화자 분리(pyannote) / 외부 LLM 보정은 `[diarize]`/`[llm]` extra + allowlist 필요.
- 이 저장소 환경(CPU-only, ffmpeg 없음)에서는 모델·ffmpeg 호출을 mock으로 검증.