Commit Graph

28 Commits

Author SHA1 Message Date
b73d27a850 feat: split author/admin detect views and add case matching KPI basis
월례회의 자료(2026-09-18) p.7 파이프라인의 3단계 「저자 화면에는 케이스 코드를
노출하지 않는다」를 구현하고, 후속 합의에 필요한 문서를 함께 남긴다.

- DetectOptions.audience(admin 기본 / author). author 직렬화에서 case_id,
  case_candidates, tags, legal_risk, is_infringement 을 제외하고 ccl_basis 를
  코드 없는 문장으로 대체한다. 일치 위치와 점수는 유지한다.
- is_infringement 는 필수 bool 로 둔다. run_precision_eval.py 등 소비자가 bool
  로 읽으므로 선택 필드로 두면 None 이 조용히 흘러간다. 제외는 직렬화에서만 한다.
- publication_verdict 필드 추가. 컴북스 코드표 미확보이므로 39건 전부 null 이며
  null 을 출간 허용으로 해석하지 않는다. enum 과 대표값 선정은 코드표 수령 후.
- request_id / taxonomy_version 을 응답에 싣는다. 관리자 확정 로그와 연결된다.
- engine_version 기본값을 2.2.1-cases-v1.3 으로 맞춘다. 직전 값(2.0.1)이 King
  운영값 2.2.0-persistent-cpu 보다 낮아 성적서 대조 시 뒤집혀 보였다.

케이스 정의는 39건(A 27건)을 유지한다. 회의 자료의 40건(A 28건)과 1건 차이가
있으나 아카이빙 DB v2.3 원본을 받기 전까지 추측해 채우지 않는다.

7,786편 운영 재검사는 모집단 불일치(현재 6,343건)로 중단했고 부분 실행은 집계하지
않는다. 별도 평가셋 재측정은 기존 testset_v2 수치(precision 98.4032%)를 그대로
재현했으며 새 독립 시험 결과가 아니다. 상세는 reports/CASE_MATCHING_EVAL_*.json.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 16:16:33 +09:00
52a0fdcdf0 feat: expand infringement case matching to v1.3 precedent mapping
태그 동점 시 첫 케이스만 반환해 나머지를 버리던 문제를 고친다.
A1·A2·A3·A4·A5·A6·A15 는 주/보조 태그가 동일하고 실제 구별자는 원본의
종류라 태그로 좁혀지지 않는다. find_case -> find_cases 로 바꿔 동점군을
전부 내보내고, 확정은 사람이 원본 종류로 한다.

- cases_v1.3.json 신설(v1.2 삭제): 39건 전부에 대표판례·처리구분(●/○) 적재.
  판례 미지정 10건은 사유를 값으로 남긴다.
- detectable_internal 10 -> 19건 (v1.3 IX장 총괄표 ● 기준으로 정정)
- _assign_tags 주 태그 조합 3 -> 5종. 유사도로 판단 가능한 쟁점만 주 태그로
  낸다. 도달 케이스 3 -> 16건(● 19건 중).
- B3·C1·D1 은 게재 사실·편집 개입·성명표시가 필요해 텍스트로 알 수 없다.
  추측하지 않고 LegalContext 대기로 두며 경계를 테스트로 고정한다.
- 케이스 수 검증을 38~39 범위에서 39 로 고정. v1.3 본문 통계 줄(●16/○22=38)이
  같은 문서의 표(●19/○20=39)와 어긋난 것이 38/39 혼재의 원인이었다.
- docs/PRECEDENT_SOURCE_GAP.md: 대표판례이나 적재본에 없어 출처를 제시할 수
  없는 14건. 응답에서도 precedents_without_source 로 구분한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 15:42:34 +09:00
c35c5aabfc feat: add anonymized infringement batch reporting 2026-09-02 09:23:45 +09:00
480f00702f feat: 전달 파일 전용 정책과 AI 표본 품질 감사 추가 2026-08-21 08:44:22 +09:00
40eede2566 feat: 요약 검수 패킷과 수기집 원본 수집 도구 추가 2026-08-20 17:24:39 +09:00
d0b5876ae5 feat: GPU 생성 작업 샤딩 지원 2026-08-20 17:19:41 +09:00
aabd7844d8 feat: 로컬 GPU AI 표본 병렬 생성 지원 2026-08-20 17:13:19 +09:00
946e9e9474 feat: 수령 자서전 데이터 파이프라인과 맞춤 요약 추가 2026-08-20 16:59:17 +09:00
5386222f1b feat: 전체 판례 검색과 판례 탭 추가 2026-08-20 16:20:37 +09:00
fa15117df7 fix: 판례 등급을 런타임 인용에 반영 2026-08-20 16:05:24 +09:00
500a4a4600 feat: 프론트에 판례 적재·인용 현황 표시
판례가 적재돼 있는지, 이번 판단에 실제로 쓰였는지가 화면에 전혀 드러나지
않았다. 엔진은 적재본 545건을 모두 로드하고 판정마다 저작물 유형·법적 태그가
맞는 상위 5건을 인용하는데, 사용자는 "판례를 쓰고 있는가"를 알 수 없었다.

세 곳에 표시한다.
  헤더 배지   ● 정상 · 코퍼스 3건 · 판례 545건
  푸터        판례 적재: 545건
  판단 카드   관련 판례 사건번호   인용 3건 / 적재 545건

적재 수를 함께 보여 주는 것이 핵심이다. "인용 3건"만 있으면 판례를 3개만
쓰는 것처럼 읽히는데, "/ 적재 545건"이 붙어야 545건 중 이 건에 맞는 3건을
고른 결과임이 드러난다.

인용 0건과 판례 미적재도 구분했다. 겉보기엔 둘 다 판례가 없지만 앞은 정상
동작이고, 뒤는 엔진이 insufficient_precedent_data 를 내며 판단 자체를
보류하는 상태다. 설정 오류일 가능성이 높아 배지를 경고색으로 바꾼다.

API 는 이미 /v1/health 의 precedent_count 와 응답의 precedent_ids 로
필요한 값을 주고 있었다. 프론트만 쓰지 않고 있었으므로 서버 변경은 없다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 14:54:51 +09:00
28c9ad1ee7 fix: 평가환경(python 3.9)에서 임포트 실패 해결
계획서 p.24 가 No.3/4/7 의 평가환경을 python 3.9 로 못박았는데, 실제로는
성능지표 평가 스크립트 3종이 전부 3.9 에서 임포트조차 되지 않았다.
python:3.9-slim 컨테이너에서 재현·수정·재검증했다.

원인: config.py 와 schemas.py 가 `from __future__ import annotations` 없이
`str | None` (PEP 604) 을 썼다. 3.10 부터의 문법이라 클래스 본문이 실행되는
순간 인터프리터가 평가하며 TypeError 로 죽는다. 이 두 파일을 타고 detector /
extractor / clustering / taxonomy / jobs.store / routes / main 이 연쇄로 깨졌다.

  No.7 eval_rouge.py       → summarizer → core.config
  No.3 eval_metadata_f1.py → extractor  → api.schemas
  No.4 evaluate_pairs.py   → detector   → api.schemas

개발환경이 3.14 라 로컬에서는 전혀 드러나지 않았다. 정답셋을 받아 측정하는
시점에 발견했다면 일정이 밀렸을 문제다.

수정은 두 가지가 모두 필요하다. future 임포트만 넣으면 pydantic 이 문자열
'str | None' 을 해석하지 못하고("Unable to evaluate type annotation"),
eval_type_backport 만 넣으면 인터프리터가 먼저 죽는다.

검증: 3.9 에서 eval_rouge.py / eval_metadata_f1.py 가 정상 실행되고 수치가
3.14 와 동일하다(ROUGE-1 recall 0.5778). evaluate_pairs.py 와 app.main 임포트도
통과. 3.14 회귀 없음.

재발 방지로 tests/test_py39_compat.py 를 추가했다. Pydantic 모델을 정의하는
모듈에 future 임포트가 있는지 AST 로 검사하므로 3.14 에서도 회귀를 잡는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 14:02:29 +09:00
3da7a0a5f2 fix: 요약 ROUGE를 계획서 수식에 맞춤 (F1 → recall, 다중 참조)
계획서 p.24 수식의 분모가 참조 n-gram 수이므로 지표는 recall 인데
eval_rouge.py 는 ROUGE-1 F1 을 목표 0.65 와 대조하고 있었다. 통상 시스템
요약이 참조보다 길면 recall > F1 이므로 우리에게 불리한 자체 기준으로
채점해 온 셈이다(내장 샘플에서 recall 0.5778 vs F1 0.5539).

같은 수식이 Σ_S∈{Reference Summaries} 로 다중 참조를 전제하는데 rouge_n /
rouge_l 은 참조를 문자열 하나만 받았다. 이제 문자열도 리스트도 받는다.
참조가 1개면 기존과 완전히 같은 값이 나오며 이를 테스트로 고정했다.

--iaa 모드를 추가했다. 사람 둘이 같은 글을 요약해도 ROUGE 는 100 이 안
나오고, 그 상한이 65 보다 낮으면 어떤 시스템도 목표를 달성할 수 없다.
정답셋 300건을 만들기 전에 파일럿 20건으로 상한을 먼저 재기 위한 것이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:54:22 +09:00
dc6c0f5d0f feat: AI 생성 표본 제작 스크립트
보유 코퍼스 31,560건이 전부 human 라벨이라 이진 판별기를 학습할 수 없고
(train_ai_detector.py 가 exit 2 로 막는다), 조사 결과 공개된 한국어 AI 생성
판별 데이터셋도 확인되지 않았다. AI 쪽 절반을 직접 만든다.

build_ai_training_dataset.py 가 외부 호출을 금지하므로 생성은 별도 스크립트로
분리했다. 프롬프트는 이미 파생된 메타데이터만 쓰고 에피소드 본문은 어떤
경로로도 API 요청에 실리지 않는다. 주석만으로는 다음 사람이 META_COLUMNS 에
본문 컬럼을 한 줄 추가하는 것을 못 막으므로, assert_no_body_columns() 가
실행 시점에 차단하고 _build_prompt() 는 본문을 넘길 파라미터 자체가 없다.

- 길이 매칭: human 분포에서 목표 길이를 뽑아 지시하고 벗어난 결과는 버린다.
  분량이 다르면 판별기가 문체가 아니라 길이를 배운다.
- 생성기 다중화: --model 반복 지정 시 라운드로빈. 1개면 그 모델만 잡는
  판별기가 되므로 경고한다.
- 문체 6종을 결정적으로 배분해 한 모델의 한 문체 암기를 막는다.
- 생성문에도 human 과 같은 normalize_ocr 을 적용한다. 한쪽만 정규화하면
  오염 방향만 뒤집힐 뿐이다.
- append 전용 + prompt_id 스킵으로 재개 가능. dry-run 은 파일시스템도
  건드리지 않는다.

--base-url 로 사내 GPU 의 OpenAI 호환 서버를 쓰면 메타데이터조차 외부로
나가지 않는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:54:21 +09:00
45355910fa feat: OCR·조판 아티팩트 정규화와 백분위 컷 캘리브레이션
학습·캘리브레이션에 쓰는 79권 코퍼스는 OCR 후처리본이라 저자 문체가 아닌
스캔·조판 흔적이 남아 있다. AI 생성 표본에는 그 흔적이 없으므로, 그대로 두면
분류기가 문체가 아니라 "OCR 흔적이 있으면 human"을 배운다. 그러면 운영에서
들어오는 깨끗한 인간 원고가 AI로 오판된다.

규칙은 추측이 아니라 코퍼스 34,105건 실측에서 뽑았다. 표본 3,000건 기준
숫자+공백+단위 94.8%, 한자 병기 99.4%, 낫표 100% 제거.
정상 한국어인 `America라는`·`3년` 형태는 건드리지 않는다.

숫자-단위 규칙은 정규식으로 밀어넣으면 `3 번지`를 `3번지`로 잘못 붙이므로
단위·접미사 화이트리스트로 판정한다.

멱등성과 "깨끗한 입력에 무해" 두 불변식을 테스트로 고정했다. 후자가 깨지면
운영 원고가 학습 코퍼스와 다르게 처리되어 정규화 자체가 새 편향이 된다.

calibrate_ai_detector_cuts.py 에 xlsx 입력과 OCR 정규화(기본 켜짐)를 추가했다.
79권 3,000건 실측 결과 low_cut 0.4286 / high_cut 0.5298, 인간 원고 기준
예상 high 비율 2.03%(설계 목표 2%)로 포화 없이 잡혔다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:53:59 +09:00
6dd5fa4a2e feat: 저작권 탭 경량 응답 API 추가 2026-08-18 12:47:51 +09:00
91e356e4c1 fix: 판례 판단 시 사람 검토 안전장치 강제 2026-08-18 11:46:46 +09:00
3debc884c1 fix: 사용자 판단 문구에서 모델명 제거 2026-08-18 11:44:56 +09:00
2be4c39a97 fix: 판례 근거 중심으로 판단 문구 개선 2026-08-18 11:41:10 +09:00
3b549dc0c0 feat: 프론트에 GPT 판례 판단 표시 2026-08-18 11:29:04 +09:00
ee2f85a2d9 feat: 판례 GPT 판단과 연동 가이드 최신화 2026-08-18 11:10:02 +09:00
a530d2139f AI 의심도 백분위 캘리브레이션 (학습·지표 없이 운영)
AI 생성 표본이 없어 정확도를 측정할 수 없는 상태에서, 규칙 기반 휴리스틱을
실제로 쓸 수 있게 만든다. 점수의 의미를 "AI일 확률"에서 "등록 코퍼스의 인간
저작물 대비 문체 이례도"로 재정의해, 라벨 없이도 참인 진술이 되도록 했다.
덤으로 high 배지 비율이 정의상 고정되어 검토 부하가 예측 가능해진다.

- ai_detector: low_cut/high_cut 주입 지원. 둘 다 주어질 때만 적용하고,
  적용되면 model_version 에 +corpus-percentile 을 붙여 컷 출처를 드러낸다.
  is_stub 은 여전히 true — 컷을 맞췄을 뿐 학습된 모델이 아니다.
- calibrate_cuts/percentile/score_text_heuristic 순수 함수 추가.
- scripts/calibrate_ai_detector_cuts.py: 코퍼스 표본의 점수 분포에서 백분위
  컷을 산출하고 .env 두 줄을 출력한다.
- 규칙 점수가 상단에서 clip 되어 p90=p98 이 되면 그 컷은 high 배지를 영원히
  0건으로 만든다. 이 경우 .env 를 출력하지 않고 exit 3 으로 중단하며
  saturated_share/distinct_scores 진단을 남긴다. 유효 표본 100건 미만은 exit 2.
- kiwipiepy 유무가 점수를 바꾸므로 실제 사용 여부를 리포트에 기록하고 경고한다.

기본값은 그대로 비활성(AI_DETECTOR_ALLOW_HEURISTIC=false)이라 켜지 않으면
동작이 바뀌지 않는다. 컷 미설정 시에는 자리표시자임을 note 로 경고한다.

테스트 180건 통과 (신규 13건).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 09:05:48 +09:00
f4461f39c7 feat: 프론트에 AI 생성 의심도 표시 2026-08-11 09:02:04 +09:00
725e44e999 Claude 리뷰 기반 운영 안정성 보강 2026-08-10 16:42:17 +09:00
ce50e89089 3.5만 에피소드 기반 표절·AI·판례 분석 파이프라인 구현 2026-08-10 16:12:15 +09:00
0472ae1f8a 2단계 고도화 선행 작업: 군집화·요약·평가환경·데이터 스펙 (데이터 수령 전)
컴북스 데이터 수령 전 가능한 작업을 선행 구현. 데이터 도착 즉시
학습·검증에 착수할 수 있도록 알고리즘·평가 하니스·문서를 준비.

알고리즘/파이프라인:
- 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>
2026-06-18 13:16:07 +09:00
4913bf3ecc API Key 인증 완전 제거
사내 운영 전제로 X-API-Key 인증을 전면 제거.
- app/core/auth.py 삭제
- routes.py에서 Depends(require_api_key) 모두 제거
- config.Settings에서 api_keys / api_key_set 제거
- .env / .env.example에서 API_KEYS 제거
- docker-compose.yml에서 API_KEYS 환경변수 제거 (KOSIMCSE_MODEL 추가)
- UI(index.html)에서 DEFAULT_API_KEY 상수 + X-API-Key 헤더 모두 제거
- scripts/sample_curl.sh, sample_python.py에서 키 헤더 제거
- tests: test_detect_requires_api_key → test_detect_no_auth_required로 갱신
- README: 인증 컬럼 제거, curl 예시에서 헤더 제거
2026-05-14 08:58:28 +09:00
3b69bdf0f0 Initial commit: O2O 저작권 침해 여부 탐지 API
PDF v1.2 요구사항 반영 완료:
- 10종 법령 메타 태그 + 39개 케이스 분류체계
- 3단 캐스케이딩: MinHash+LSH → 삼중 유사도 → 분류
- 자서전 특화: 공통 표현 사전 제거 + NER 마스킹
- KoSimCSE 한국어 임베딩 (자체 산출물 방어)
- 보수적 임계값 0.85
- 검토 콘솔 UI (탐지 + 코퍼스 관리 탭)
- Docker 배포 패키지 + 31개 테스트 통과
2026-05-13 11:20:17 +09:00