컴북스 데이터 수령 전 가능한 작업을 선행 구현. 데이터 도착 즉시 학습·검증에 착수할 수 있도록 알고리즘·평가 하니스·문서를 준비. 알고리즘/파이프라인: - engine/clustering.py: 군집화 기반 부분 표절(요소 교체) 판별, detect 응답에 partial_signal 필드 노출 (계획서 2단계 표절검출 고도화) - engine/summarizer.py + POST /v1/summary: TextRank 추출적 요약 + 통합(LLM) 골격 (과제2 ② 스토리 요약/분석) - engine/preference.py + scripts/build_preference_dataset.py: Human Feedback 선호학습(DPO) 데이터 파이프라인 골격 평가 하니스 (정답셋 도착 즉시 측정): - engine/rouge.py + scripts/eval_rouge.py: 요약 ROUGE (지표 No.7) - engine/metadata_eval.py + scripts/eval_metadata_f1.py: 메타 추출 F1 (지표 No.3, KLUE NER 호환) - engine/case_coverage.py + scripts/analyze_case_coverage.py: 39 케이스 갭 분석 → 컴북스 데이터 요청 목록 (정밀도 97% 근거) 문서: - docs/DATA_REQUEST_SPEC.md: 요청 데이터 스펙 + 요약 정답셋/HF 라벨 가이드 - docs/INTEGRATION_INTERFACE.md: 2단계 통합 인터페이스 - docs/SW_COPYRIGHT_REGISTRATION.md: SW 저작권 등록 준비 - docs/PHASE2_PROGRESS.md, docs/CASE_COVERAGE.md 테스트 31 → 67건 전부 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
77 lines
3.3 KiB
Python
77 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""39개 침해 케이스 커버리지 갭 분석 — 컴북스 데이터 요청 근거 산출.
|
|
|
|
데이터 없이 지금 실행 가능: taxonomy(분류체계)만으로 '탐지 대상이나 샘플이 없는
|
|
케이스' 목록을 뽑아 정밀도 97% 달성을 위해 요청할 데이터를 케이스 단위로 정리한다.
|
|
|
|
옵션으로 케이스별 보유 샘플 수 파일을 주면 실제 커버리지를 계산한다.
|
|
샘플 수 파일 형식 (JSON): {"A1": 12, "A2": 0, ...}
|
|
|
|
사용:
|
|
python -m scripts.analyze_case_coverage
|
|
python -m scripts.analyze_case_coverage --samples data/eval/case_counts.json
|
|
python -m scripts.analyze_case_coverage --md > docs/CASE_COVERAGE.md
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from app.core.config import get_settings # noqa: E402
|
|
from app.engine.case_coverage import analyze_coverage # noqa: E402
|
|
from app.engine.taxonomy import load_taxonomy # noqa: E402
|
|
|
|
|
|
def main() -> None:
|
|
ap = argparse.ArgumentParser(description="39 케이스 커버리지 갭 분석")
|
|
ap.add_argument("--samples", default=None, help="케이스별 보유 샘플 수 JSON")
|
|
ap.add_argument("--md", action="store_true", help="Markdown 표로 출력")
|
|
args = ap.parse_args()
|
|
|
|
tax = load_taxonomy(get_settings().taxonomy_path)
|
|
if tax is None:
|
|
print("taxonomy 로드 실패", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
counts = None
|
|
if args.samples and Path(args.samples).exists():
|
|
counts = json.loads(Path(args.samples).read_text(encoding="utf-8"))
|
|
|
|
rep = analyze_coverage(tax.cases, counts)
|
|
|
|
if args.md:
|
|
print("# 39개 침해 케이스 커버리지 갭 분석\n")
|
|
print(f"- 전체 케이스: {rep['total_cases']}")
|
|
print(f"- 엔진 탐지 대상: {rep['detectable_cases']}")
|
|
print(f"- 평가 샘플 보유(covered): {rep['covered_cases']}")
|
|
print(f"- 탐지 대상이나 데이터 없음(요청 대상): {rep['need_data_cases']}")
|
|
print(f"- 커버리지: {rep['coverage_ratio']:.1%}\n")
|
|
print("| case_id | subgroup | actor | 탐지대상 | 샘플수 | 상태 |")
|
|
print("|---|---|---|---|---|---|")
|
|
for r in rep["rows"]:
|
|
print(f"| {r.case_id} | {r.subgroup} | {r.actor} | "
|
|
f"{'O' if r.detectable else '-'} | {r.sample_count} | {r.status} |")
|
|
return
|
|
|
|
print("\n=== 39개 침해 케이스 커버리지 ===")
|
|
print(f"전체 {rep['total_cases']} / 탐지대상 {rep['detectable_cases']} / "
|
|
f"covered {rep['covered_cases']} / 요청대상 {rep['need_data_cases']} / "
|
|
f"커버리지 {rep['coverage_ratio']:.1%}")
|
|
|
|
print("\n[데이터 요청 대상 — 탐지 가능하나 샘플 없는 케이스]")
|
|
if not rep["data_request_list"]:
|
|
print(" (없음 — 모든 탐지대상 케이스에 샘플 보유)")
|
|
for item in rep["data_request_list"]:
|
|
print(f" - {item['case_id']:<4} {item['subgroup']} [{item['actor']}]")
|
|
|
|
print("\n※ '탐지 대상이나 데이터 없음' 케이스가 정밀도 97% 달성을 위한 컴북스 요청 데이터 목록입니다.")
|
|
print(" out_of_engine_scope(유족/플랫폼/약관 등)는 탐지 모듈 범위 밖 → 데이터 불필요.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|