--- phase: P8 title: "음성 transcription + timestamp citation" status: planned depends_on: [P5] source: kebab_local_rust_report.md §9.3, §17 Phase 8 --- # P8 — 음성 ingestion ## 목표 audio 파일 → transcript (timestamped segment) → CanonicalDocument → 동일 검색/RAG 파이프라인. citation 은 `meeting.m4a:00:13:42-00:14:10`. ## 산출 crate - `kebab-parse-audio` — `Extractor` 구현. - `kebab-asr-whisper` (또는 `kebab-parse-audio` 내부 모듈) — whisper.cpp adapter. ## 파이프라인 (§9.3) ```text audio file -> (선택) decode/resample -> whisper.cpp transcription -> timestamped segments -> (선택) speaker diarization -> CanonicalDocument ``` ## ASR 엔진 - 1차: whisper.cpp. Apple Silicon (Metal/Core ML/Accelerate) 가속 지원, M4 MacBook 적합. - Rust binding 또는 sidecar binary. abstract trait `Transcriber` 로 둘 다 수용. - 모델 선택: `large-v3` 정확도 우선, `medium`/`small` 속도 우선. config. ```rust pub trait Transcriber { fn model_id(&self) -> &str; fn transcribe(&self, audio: &AudioInput) -> anyhow::Result; } pub struct Transcript { pub segments: Vec, pub language: Lang, pub model_id: String, pub model_version: String, } pub struct TranscriptSegment { pub start_ms: u64, pub end_ms: u64, pub text: String, pub speaker: Option, pub confidence: Option, } ``` ## Diarization (선택, 후순위) - 화자 분리 (pyannote 등) → `speaker = "S1" | "S2" | ...`. - 1차 구현에서는 single speaker 가정. trait 만 마련. ## CanonicalDocument 매핑 오디오 1개 = 1 document. blocks: ```rust Block::AudioRef(AudioRefBlock { asset_id, duration_ms: u64, transcript_segments: Vec, transcript_engine: String, transcript_engine_version: String, }) ``` 전체 transcript 를 한 덩어리 텍스트로도 보관 (검색 편의). ## Chunking - segment 인접 그룹핑 → target_tokens 도달까지 합침. - 합칠 때 첫 segment 의 `start_ms`, 마지막 segment 의 `end_ms` 가 chunk 의 `source_span`. - 발화자 전환 시점에서 우선 분할 (있을 경우). - chunker version: `audio-segment-v1`. ## Citation 형식 ```text meeting-2026-04-27.m4a:00:13:42-00:14:10 meeting-2026-04-27.m4a:00:13:42-00:14:10:speaker=S1 ``` ## CLI ```text kebab ingest ./meeting.m4a kebab ingest ./recordings/ kebab search "회의에서 언급한 결정사항" kebab inspect doc # transcript + segment timestamp 표시 kebab play # (선택) 해당 구간 재생 — 후순위 ``` ## 테스트 - fixture: 짧은 한국어 오디오, 영문 오디오, 한영 코드 스위칭, 잡음 포함. - transcript timestamp 단조 증가. - chunk 의 `source_span` 이 실제 segment 시간과 일치. - 동일 오디오 재수집 idempotent (asset_id = blake3). - 큰 파일 streaming 처리 (RAM 폭주 방지). ## 의존성 경계 - `kebab-parse-audio` 는 `kebab-core` + `Transcriber` adapter 만. - LLM 호출 금지. RAG 단계는 transcript text 기반으로 동일 파이프라인. ## 완료 조건 - [ ] `kebab ingest