사내 운영 전제로 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 예시에서 헤더 제거 |
||
|---|---|---|
| app | ||
| data | ||
| reports | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| Dockerfile | ||
| README.md | ||
| docker-compose.yml | ||
| requirements.txt | ||
| 나누구_저작권침해_아카이빙_실무방안_v1.2.docx | ||
| 나누구_저작권침해_아카이빙_실무방안_v1.2.pdf | ||
README.md
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 # 자서전 빈출 표현 사전