cd2f807557
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
379 lines
13 KiB
JSON
379 lines
13 KiB
JSON
{
|
|
"version": "1.0.0",
|
|
"lastScanned": 1780919472386,
|
|
"projectRoot": "/root/luke_scribe",
|
|
"techStack": {
|
|
"languages": [
|
|
{
|
|
"name": "Python",
|
|
"version": null,
|
|
"confidence": "high",
|
|
"markers": [
|
|
"pyproject.toml"
|
|
]
|
|
}
|
|
],
|
|
"frameworks": [
|
|
{
|
|
"name": "fastapi",
|
|
"version": null,
|
|
"category": "backend"
|
|
},
|
|
{
|
|
"name": "pytest",
|
|
"version": null,
|
|
"category": "testing"
|
|
}
|
|
],
|
|
"packageManager": null,
|
|
"runtime": null
|
|
},
|
|
"build": {
|
|
"buildCommand": null,
|
|
"testCommand": "export PATH=\"$HOME/.local/bin:$HOME/.cargo/bin:$PATH\"\necho \"=== ruff ===\"; uv run ruff check src/ tests/ && echo clean\necho \"=== pytest ===\"; uv run pytest -q 2>&1 | tail -2\necho \"=== --correct 경로(설정 없음 → 우아한 에러) ===\"\nuv run luke-scribe transcribe /tmp/jfk.flac --model tiny --language en --correct 2>&1 | tail -4; echo \"exit=${PIPESTATUS[0]}\"",
|
|
"lintCommand": "ruff check",
|
|
"devCommand": null,
|
|
"scripts": {}
|
|
},
|
|
"conventions": {
|
|
"namingStyle": null,
|
|
"importStyle": null,
|
|
"testPattern": null,
|
|
"fileOrganization": null
|
|
},
|
|
"structure": {
|
|
"isMonorepo": false,
|
|
"workspaces": [],
|
|
"mainDirectories": [
|
|
"src",
|
|
"tests"
|
|
],
|
|
"gitBranches": null
|
|
},
|
|
"customNotes": [
|
|
{
|
|
"timestamp": 1780801973941,
|
|
"source": "manual",
|
|
"category": "architecture",
|
|
"content": "내부용 로컬 STT 전사 API. 단일 Job 추상화 + 2레인: 배치=Redis/RQ SimpleWorker(no-fork, model-load-once), 실시간=WebSocket LocalAgreement(turbo). 엔진=faster-whisper(CTranslate2). 부팅 시 VRAM 실측→능력등급 T0(CPU)~T3(turbo+large-v3 동시상주). 배포 2프로파일: Colab/dev=순수 Python·in-proc 큐·cloudflared / prod=Docker+Redis+공유스토어. 입력 상한 4h/2GB(초과 413), 큐 만재 429."
|
|
},
|
|
{
|
|
"timestamp": 1780801976315,
|
|
"source": "manual",
|
|
"category": "techstack",
|
|
"content": "Python 3.11+, uv(패키지), FastAPI+uvicorn, faster-whisper(CTranslate2: turbo+large-v3), Redis+RQ(no-fork), pydantic v2, ffmpeg, Silero VAD; 옵션 pyannote(diarize)/LLM 보정(local·external)/cloudflared. CLI=typer(detect/transcribe/bench/serve), 테스트=pytest, src 레이아웃 src/luke_scribe/. ⚠️ 전부 plan v2.3상 결정이며 아직 미구현(P1+에서 생성)."
|
|
},
|
|
{
|
|
"timestamp": 1780801980334,
|
|
"source": "manual",
|
|
"category": "env",
|
|
"content": "git 원격=자체호스팅 Gitea https://git.lukehemmin.com (openresty, HTTPS/443 전용, SSH 미노출). 인증=PAT를 ~/.git-credentials에 저장(global helper store, username lukehemmin) — 검증완료, VS Code askpass 없이 push 됨. ⚠️ 저장소 익명 읽기 허용 상태(내부/비공개 의도면 Gitea에서 Private 점검)."
|
|
},
|
|
{
|
|
"timestamp": 1780812476362,
|
|
"source": "manual",
|
|
"category": "status",
|
|
"content": "P1 진행(2026-06-07): ✅ detect(능력등급 T0~T3, 1050→T0_CPU 명시강등) · ✅ transcribe(faster-whisper CPU 검증: JFK 11s 클립 정확 전사, model_used 출력) · 단위테스트 10개 통과. 코드 존재함(더 이상 0%). 남음: word-ts/format 출력옵션·Silero VAD 옵션화, VRAM 실측 probe(정적추정 대체), bench(라벨 KO+EN 샘플셋 필요), 상위 tier(T2/T3) Colab 검증, P2(API+Redis/RQ). 브랜치 feat/p1-core."
|
|
},
|
|
{
|
|
"timestamp": 1780926195887,
|
|
"source": "manual",
|
|
"category": "finding",
|
|
"content": "검증된 발견(2026-06-07): KO+EN 혼용어 음차 문제의 open-vocab 해법 = 사내 GPT-4o 텍스트 후처리 보정. faster-whisper(turbo)가 음차로 망친 영문 용어를 hotwords 등록 없이 문맥+지식으로 복원. 실증(EmbeddingGemma 강연 90초 슬라이스): 인베딩 점마→Embedding Gemma, 재미나이→Gemini, 점마→Gemma, 랭기징→Language, 구글 포 디벨로퍼스→Google for Developers (5/5, 일반 한국어는 보존). 게이트=OpenAI 호환(baseURL http://192.168.0.123:8080/v1, model copilot-gpt-4o, API키 필요·키는 메모리에 저장 안 함; localhost:8080은 사용자 머신 터널이라 샌드박스선 미도달) → 사내 호출이라 외부 egress 0(프라이버시 OK). 함의: hotwords는 등록된 것만 잡아 불충분, LLM 문맥보정이 '모르는 용어'까지 커버. 단서: (1) 'Embedding Gemma' 띄어쓰기(공식 EmbeddingGemma)→rules/glossary 정규화 병행 필요, (2) LLM이 아는/추론가능 용어만·초신조어는 confidence 플래그→휴먼, (3) 샘플1개라 과교정 추가검증, (4) 게이트 경로 불안정(401→timeout→reset)→재시도 필요(스크립트에 반영). 작은 컨텍스트는 청크+러닝글로서리로 우회. PoC=scripts/llm_correct.py → 승격 대상 postprocess/llm.py(confidence-gated·청크·backend=internal·감사로그) + transcribe --correct 플래그."
|
|
}
|
|
],
|
|
"directoryMap": {
|
|
"samples": {
|
|
"path": "samples",
|
|
"purpose": null,
|
|
"fileCount": 1,
|
|
"lastAccessed": 1780919472362,
|
|
"keyFiles": [
|
|
"README.md"
|
|
]
|
|
},
|
|
"src": {
|
|
"path": "src",
|
|
"purpose": "Source code",
|
|
"fileCount": 0,
|
|
"lastAccessed": 1780919472371,
|
|
"keyFiles": []
|
|
},
|
|
"tests": {
|
|
"path": "tests",
|
|
"purpose": "Test files",
|
|
"fileCount": 2,
|
|
"lastAccessed": 1780919472373,
|
|
"keyFiles": [
|
|
"test_device_manager.py",
|
|
"test_engine_audio.py"
|
|
]
|
|
}
|
|
},
|
|
"hotPaths": [
|
|
{
|
|
"path": "src/luke_scribe/cli.py",
|
|
"accessCount": 8,
|
|
"lastAccessed": 1780957705972,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/config.py",
|
|
"accessCount": 5,
|
|
"lastAccessed": 1780957473801,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "scripts/llm_correct.py",
|
|
"accessCount": 4,
|
|
"lastAccessed": 1780925584647,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "pyproject.toml",
|
|
"accessCount": 4,
|
|
"lastAccessed": 1780928043613,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "README.md",
|
|
"accessCount": 3,
|
|
"lastAccessed": 1780812417055,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/postprocess/llm.py",
|
|
"accessCount": 3,
|
|
"lastAccessed": 1780956524689,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/routes/transcribe.py",
|
|
"accessCount": 3,
|
|
"lastAccessed": 1780956549345,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "tests/test_postprocess.py",
|
|
"accessCount": 2,
|
|
"lastAccessed": 1780956556589,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804261889,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/devices/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804263611,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/devices/profile.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804266795,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/devices/vram_probe.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804273484,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/devices/manager.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804300531,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "run.sh",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804312249,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": ".env.example",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804316978,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "tests/test_device_manager.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780804449331,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/engine/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812252757,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/engine/model_registry.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812254912,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/engine/faster_whisper_engine.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812261152,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/audio/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812262920,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/audio/ingest.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812299865,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "tests/test_engine_audio.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812413312,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "samples/README.md",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812722445,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "samples/ko_en/manifest.jsonl.example",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780812854083,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/results/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927886298,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/results/formats.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927892282,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/postprocess/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927894092,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/postprocess/rules.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927897308,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927952439,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/schemas.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927953308,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/engine_pool.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927954191,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/deps.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927955218,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/app.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927956175,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/api/routes/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927957095,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/connectivity/__init__.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927962648,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "src/luke_scribe/connectivity/tunnel.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780927971385,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "tests/test_formats.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780928016400,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "tests/test_api.py",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780928028187,
|
|
"type": "file"
|
|
},
|
|
{
|
|
"path": "COLAB.md",
|
|
"accessCount": 1,
|
|
"lastAccessed": 1780957731994,
|
|
"type": "file"
|
|
}
|
|
],
|
|
"userDirectives": [
|
|
{
|
|
"timestamp": 1780801958149,
|
|
"directive": "`.omc/`의 기획 산출물(plans/specs/artifacts)이 공유 저장소의 단일 진실원본(SoT)이다 — 항상 in-repo로 최신화해 다른 직원이 OMC로 프로젝트를 즉시 이해하게 한다. 결정 변경 시 SoT 문서와 본 프로젝트 메모리를 함께 갱신한다.",
|
|
"context": "SoT: .omc/plans/consensus-luke-scribe-stt-api.md (v2.3), .omc/specs/deep-interview-luke-scribe-stt-api.md",
|
|
"source": "explicit",
|
|
"priority": "high"
|
|
},
|
|
{
|
|
"timestamp": 1780801959067,
|
|
"directive": "greenfield 상태 — 소스코드 0%. build/test 명령이 동작한다고 단정 금지. 다음 단계는 P1(uv 스캐폴딩 + Device Manager/VRAM probe + CLI detect/bench)이며 구현 시작 시 feat/p1-core 브랜치 사용.",
|
|
"context": "현재 git 커밋 2개(초기 + v2.3 문서)만 존재. src/·pyproject.toml 아직 없음.",
|
|
"source": "explicit",
|
|
"priority": "high"
|
|
},
|
|
{
|
|
"timestamp": 1780801959846,
|
|
"directive": "확정된 설계 결정(재논쟁 금지): (1) 모델=기본 turbo 단일, P1 bench에서 혼용어 entity 보존율<95%일 때만 하이브리드(batch=large-v3) 채택; (2) 취소=협조적 세그먼트 경계만(hard-kill 없음); (3) 배포HW·동시성 N=하드웨어 적응형 자동산정(고정 타깃 없음); (4) 프라이버시 우선=모든 종료경로 finally에서 원본+파생 오디오 삭제, 결과 7일 TTL, 외부 LLM egress 기본 off(allowlist+opt-in+감사로그).",
|
|
"context": "",
|
|
"source": "explicit",
|
|
"priority": "high"
|
|
},
|
|
{
|
|
"timestamp": 1780801960639,
|
|
"directive": "남은 설계 모호도(~5%)는 측정 게이트형 — 추가 인터뷰가 아니라 P1 bench로 닫는다: AC-4 R-WER 기준선, 하이브리드→단일 확정, CT2 GIL→실시간 프로세스 분리 여부.",
|
|
"context": "",
|
|
"source": "explicit",
|
|
"priority": "normal"
|
|
}
|
|
]
|
|
} |