AI 출판과제 - 저작권 침해 여부 판단
성능지표 #4(표절 판별 정밀도) 를 공인시험에서 재현할 수 있게 시험셋 생성기, 평가 실행기, python 3.9 평가 컨테이너, 시험절차서를 둔다. 시험셋은 작성자 단위로 코퍼스를 나눠 만든다. 비표절 시료를 참조 코퍼스에서 뽑으면 인덱스가 자기 자신을 찾아 전부 오탐이 되므로, 인덱스에 없는 작성자의 글만 쓴다. 무관한 글만 넣으면 정밀도가 부풀려져 주제 근접 시료 150건을 따로 섞는다. 실제 오탐이 나는 유형이 그것이다. 대필(인칭 전환)은 제외한다. 원문이 그대로 남지만 표절 여부가 계약·동의로 갈려 텍스트만으로 판정할 수 없다. 자체 측정 결과 정밀도 0.9840 (TP=493 FP=8 TN=492 FN=7). 목표 0.97 을 넘고, 오탐 8건 중 7건이 주제 근접 시료에서 나와 난이도가 운영 조건을 반영한다. 시험셋에는 자서전 원문이 들어가므로 저장소에 두지 않는다. 시드가 manifest 에 고정돼 있어 생성기로 동일하게 재생성된다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| app | ||
| data | ||
| docs | ||
| reports | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| Dockerfile.eval | ||
| Dockerfile.gpu-embed | ||
| README.md | ||
| requirements.txt | ||
O2O 저작권 침해 여부 탐지 API
KOCCA 출판환경변화 과제 2단계 - 오투오 산출물. 자서전 본문을 입력하면 저작권 침해 여부를 판정해 법령 기반 메타 태그와 케이스 ID로 반환합니다.
기능
- 삼중 유사도 탐지 — 표면(임베딩) + 구조(형태소 lemma 교집합) + 요소(인물·모티프) 결합 판정
- 3단 캐스케이딩 — MinHash+LSH 1차 필터 → 정밀 비교 → 침해 유형 분류
- 법령 기반 10종 메타 태그 — 복제권 / 공중송신권 / 배포권 / 2차적저작물작성권 / 공표권 / 성명표시권 / 동일성유지권 / 인용 표시 누락 / 자기 창작인 양 표시 / 2차적저작물 미달 가공
- 39개 침해 케이스 자동 매핑 — 그룹 A(저자 가해) ~ X(분류체계 외)
- 자서전 특화 처리 — 공통 표현 사전 제거 + NER 마스킹으로 오탐 방지
- 검토 콘솔 웹 UI — 브라우저에서 본문 입력·검사·결과 분석, 코퍼스 관리
- 코퍼스 직접 관리 — 사용자가 자서전을 직접 업로드/삭제, 인덱스 자동 재빌드
- 배치 처리 — 비동기 잡으로 최대 500건 일괄 검사
빠른 시작
Docker
cp .env.example .env
# .env 에서 HOST/PORT/LOG_LEVEL/OPENAI_API_KEY 등 조정 (선택)
docker compose up --build
로컬 (Python 3.13 권장)
python3.13 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# .env 의 HOST/PORT 따라 실행
python -m app.main
# 또는 일회성 override
PORT=9000 LOG_LEVEL=debug python -m app.main
# 또는 uvicorn 직접
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
접속:
http://localhost:{PORT}/— 검토 콘솔 (브라우저용)http://localhost:{PORT}/docs— API 명세 (Swagger)
.env 의 서버 바인딩 변수:
| 변수 | 기본 | 설명 |
|---|---|---|
HOST |
0.0.0.0 |
바인딩 호스트 |
PORT |
8000 |
포트 |
LOG_LEVEL |
info |
debug/info/warning/error |
RELOAD |
false |
파일 변경 시 자동 재시작 (개발용) |
사용법
1. 브라우저에서 사용 (검토 콘솔)
http://localhost:8000/ 접속.
[탐지 검토] 탭
- 본문 텍스트 붙여넣기 (또는 샘플 시나리오 버튼 클릭)
- "검사 시작" → 결과 표시
- 큰 판정 배지 (침해 여부 + 결합 유사도 %)
- 점수 분석 (text / lemma / character / motif 4개 막대)
- 매칭된 레퍼런스 + 법령 태그 chip (주/보조) + 케이스 ID
- 본문에 일치 구간 하이라이트
[코퍼스 관리] 탭
- 좌측 폼에서 자서전 신규 등록 (제목 + 본문 또는 .txt 파일)
- 우측 테이블에서 등록된 자서전 확인 / 삭제
- 업로드/삭제 시 인덱스 자동 재빌드
2. API로 사용 (curl)
# 탐지
curl -X POST http://localhost:8000/v1/plagiarism/detect \
-H "Content-Type: application/json" \
-d '{
"doc_id": "test-001",
"text": "검사할 본문 텍스트…",
"metadata": {"title": "작품명", "author": "저자"}
}'
# 자서전 업로드
curl -X POST http://localhost:8000/v1/corpus \
-H "Content-Type: application/json" \
-d '{"title": "김OO 자서전", "text": "본문…"}'
# .txt 파일 업로드
curl -X POST http://localhost:8000/v1/corpus/file \
-F "title=김OO 자서전" \
-F "file=@autobiography.txt"
# 코퍼스 목록
curl http://localhost:8000/v1/corpus
# 분류체계 조회 (10종 태그 + 39 케이스)
curl http://localhost:8000/v1/taxonomy
엔드포인트 요약
| Method | Path | 용도 |
|---|---|---|
| GET | / |
검토 콘솔 (HTML) |
| GET | /docs |
Swagger UI |
| GET | /v1/health |
헬스체크 + 엔진 정보 |
| GET | /v1/taxonomy |
분류체계 조회 |
| POST | /v1/plagiarism/detect |
단건 동기 탐지 |
| POST | /v1/plagiarism/batch |
배치 잡 등록 (≤500건) |
| GET | /v1/plagiarism/batch/{job_id} |
배치 결과 조회 |
| GET | /v1/corpus |
코퍼스 목록 |
| POST | /v1/corpus |
JSON 업로드 |
| POST | /v1/corpus/file |
.txt 파일 업로드 |
| DELETE | /v1/corpus/{doc_id} |
삭제 |
응답 스키마 (탐지 결과)
{
"doc_id": "test-001",
"is_infringement": true,
"confidence": 0.85,
"extracted_elements": {
"characters": ["..."],
"motifs": ["..."],
"genre": "...",
"keywords": ["..."]
},
"matches": [{
"source_doc": "ref-0001",
"source_title": "원본 작품명",
"similarity": 0.85,
"tags": [
{"tag": "reproduction", "role": "primary", "label_ko": "복제권"},
{"tag": "citation_missing", "role": "primary", "label_ko": "인용 표시 누락"},
{"tag": "public_transmission", "role": "secondary", "label_ko": "공중송신권"}
],
"case_id": "A1",
"case_title": "시·노래 가사 본문 무단 인용",
"evidence_spans": [{"start": 21, "end": 34, "matched": "…"}],
"score_breakdown": {
"text_sim": 0.43, "lemma_sim": 0.75,
"character_sim": 0.0, "motif_sim": 0.67,
"lsh_jaccard": 0.07
}
}],
"ccl_basis": "…",
"autobiography_mode": true,
"engine_version": "o2o-plagiarism-2.0.0-pdf-v1.2"
}
환경변수 (.env)
| 변수 | 기본 | 설명 |
|---|---|---|
SIMILARITY_THRESHOLD |
0.85 |
침해 판정 임계값 (정밀도 우선) |
AUTOBIOGRAPHY_MODE |
true |
자서전 특화 전처리 (공통표현+NER) |
USE_LSH_FILTER |
true |
MinHash+LSH 1차 필터 |
USE_LLM_EXTRACTOR |
false |
OpenAI 기반 요소 추출 (키 필요) |
USE_EMBEDDING_SIMILARITY |
false |
OpenAI 임베딩 유사도 (키 필요) |
OPENAI_API_KEY |
(빈값) | 비우면 룰 기반 + TF-IDF 폴백 |
WEIGHT_TEXT_SIM 등 |
0.30/0.45/0.15/0.10 | 삼중 유사도 가중치 (합 1.0) |
요청 단위 override 가능 항목:
options.threshold— 임계값options.autobiography_mode— 자서전 모드 ON/OFF
테스트
pytest tests/ -v
# 31 passed — API, 삼중 유사도, 형태소 분석, PDF 분류체계, LSH, 자서전 필터, 다중 태그 부여
디렉토리 구조
app/
├── main.py # FastAPI 앱
├── api/{routes,schemas}.py # 엔드포인트 + Pydantic 모델
├── core/{config,auth}.py # 설정 + API Key 인증
├── engine/
│ ├── detector.py # 탐지 파이프라인 오케스트레이션
│ ├── extractor.py # 콘텐츠 요소 추출 (룰 또는 OpenAI)
│ ├── similarity.py # 삼중 유사도 + TF-IDF/임베딩 백엔드
│ ├── structural.py # 형태소 lemma 교집합
│ ├── lsh_filter.py # MinHash+LSH 1차 필터
│ ├── autobiography_filter.py # 자서전 공통표현 제거 + NER 마스킹
│ ├── corpus.py # 코퍼스 CRUD
│ └── taxonomy.py # 10종 태그 + 39 케이스 매핑
├── jobs/store.py # 배치 잡 in-memory 스토어
└── static/index.html # 검토 콘솔 UI
data/
├── reference/ # 자서전 코퍼스 (업로드 저장 위치)
├── taxonomy/{meta_tags,cases}.json # PDF v1.2 분류체계
└── autobiography/common_patterns.txt # 자서전 빈출 표현 사전