# 저작권 탐지 API 양식서 (오투오 → 바이칼) > 나누구 앱 **저작권 탭** 연동용 API 계약. 본문 입력 → 표절 탐지 결과 + 저작권 탭 > 표시 항목을 반환한다. 본 문서 기준으로 UI를 연동하면 된다. > 엔진: `o2o-plagiarism-api` --- ## 0. 기본 정보 | 항목 | 값 | |---|---| | Base URL (개발/통합 테스트) | `https://plagiarism.o2o.kr` | | 프로토콜 | HTTPS, `Content-Type: application/json` (UTF-8) | | 인증 | 개발 단계 없음 → **운영 전 API 키/토큰 추가 예정** | | Swagger(자동 명세) | `{BASE}/docs` — 실시간 스키마 확인 가능 | | 실서비스 배포 | 개인정보(자서전) 보호를 위해 **Docker 온프레미스 납품** 예정 (실사용자 본문은 오투오 서버로 전송 안 함) | --- ## 1. 저작권 탭 화면 ↔ API 필드 매핑 (핵심) 나누구 저작권 탭의 각 표시 항목은 경량 응답에서 그대로 읽으면 된다. **별도 계산 불필요** — 독창성 환산과 한글 라벨까지 서버가 완료해 제공한다. | 화면 표시 | 예시 | API 필드 | |---|---|---| | 독창성 **98%** | 98 | `copyright.originality_percent` | | 저작권 · 유사도 **2%** | 2 | `copyright.similarity_percent` | | 유사 문장 **0건** | 0건 | `similar_sentences.label` | | 대조 결과 설명 | 문장 | `copyright.description` | | 표절 의심 구간 **없음** | false | `copyright.has_suspicion` | | AI 생성 의심도 **낮음** | 낮음 | `ai_generation_suspicion.label` | | 판례 판단 | 침해 의심 낮음 | `legal_judgment.label` | | 판례 근거 | 사건번호 포함 문장 | `legal_judgment.summary` | > `ai_generation_suspicion.level` 값은 `low`, `medium`, `high`, `unknown`이며, > 화면은 함께 반환되는 한글 `label`을 그대로 표시한다. --- ## 2. 저작권 탭 경량 검사 — `POST /v1/plagiarism/review` 모바일 저작권 탭은 이 API를 사용한다. 내부 상세 탐지 결과 중 화면에 필요한 독창성, 유사도, 대조 건수, 유사 문장 수, AI 의심도, 판례 판단만 반환한다. 요청 형식은 기존 `POST /v1/plagiarism/detect`와 동일하며 응답 계약은 `docs/API_GUIDE_BAIKAL.md`를 따른다. ## 3. 상세 표절 탐지 — `POST /v1/plagiarism/detect` 본문 1건을 검사한다. ### 요청 ```json { "doc_id": "episode-001", "text": "창밖으로 보이는 숲은 오늘따라 유난히 푸르게 보였다. ...", "metadata": { "title": "에피소드 1", "author": "홍길동", "genre": "자서전" }, "options": { "return_evidence": true, "threshold": null, "top_k": 5, "autobiography_mode": null } } ``` | 필드 | 타입 | 필수 | 설명 | |---|---|---|---| | `doc_id` | string | ✅ | 호출측 문서 식별자 (응답에 그대로 반환) | | `text` | string | ✅ | 검사할 본문 (1자 이상) | | `metadata` | object | – | `title`/`author`/`genre`/`publisher`/`publication_year` (모두 선택) | | `options.return_evidence` | bool | – | 일치 구간 하이라이트 반환 (기본 true) | | `options.threshold` | float\|null | – | 판정 임계값. null이면 서버 기본(0.85) | | `options.top_k` | int | – | 최대 매칭 수 (기본 5) | | `options.autobiography_mode` | bool\|null | – | 자서전 특화 전처리. null이면 서버 설정 | ### 응답 (저작권 탭에 표시되는 "깨끗한 글" 예시) ```json { "doc_id": "episode-001", "is_infringement": false, "confidence": 0.32, "review_summary": { "originality_percent": 98, "similarity_percent": 2, "similar_sentence_count": 0, "compared_count": 35000, "has_suspicion": false, "ai_suspicion_level": "low" }, "ai_generation": { "suspicion_level": "low", "score": 0.06, "is_stub": true, "available": false, "model_version": "unavailable", "note": "학습된 모델이 없어 채점하지 않음" }, "matches": [], "extracted_elements": { "characters": [], "motifs": [], "genre": "자서전", "keywords": ["정원", "숲"] }, "ccl_basis": null, "autobiography_mode": true, "candidates_before_filter": 0, "engine_version": "o2o-plagiarism-2.1.0-kosimcse", "analyzed_at": "2026-08-04T09:30:00Z" } ``` ### 응답 (표절이 탐지된 경우 — matches가 채워짐) ```json { "doc_id": "episode-002", "is_infringement": true, "confidence": 0.88, "review_summary": { "originality_percent": 45, "similarity_percent": 55, "similar_sentence_count": 1, "compared_count": 35000, "has_suspicion": true, "ai_suspicion_level": "low" }, "ai_generation": { "suspicion_level": "unknown", "score": null, "available": false, "is_stub": false, "model_version": "unavailable", "note": "학습된 모델이 없어 채점하지 않음" }, "matches": [ { "source_doc": "auto-0003", "source_title": "○○○ 자서전", "similarity": 0.88, "tags": [ { "tag": "reproduction", "role": "primary", "label_ko": "복제권" }, { "tag": "citation_missing", "role": "primary", "label_ko": "인용 표시 누락" } ], "case_id": "A6", "case_title": "유명인 자서전 일부 베끼기", "infringement_type": "copy", "evidence_spans": [ { "start": 12, "end": 48, "matched": "일치한 본문 구간 ..." } ], "score_breakdown": { "text_sim": 0.86, "lemma_sim": 0.94, "character_sim": 0.8, "motif_sim": 0.7, "lsh_jaccard": 0.62 }, "partial_signal": { "cluster_id": 2, "verdict": "element_swap_plagiarism", "signature_score": 0.74, "per_element": { "lemmas": 0.92, "keywords": 0.88, "characters": 0.0, "motifs": 0.1 }, "retained_elements": ["lemmas", "keywords"], "changed_elements": ["characters", "motifs"] } } ], "ccl_basis": "'○○○ 자서전'와 결합 유사도 88%로 매칭. 주 침해 태그: 복제권, 인용 표시 누락. 추정 케이스 A6 ...", "autobiography_mode": true, "candidates_before_filter": 4, "engine_version": "o2o-plagiarism-2.1.0-kosimcse", "analyzed_at": "2026-08-04T09:31:00Z" } ``` ### 응답 필드 상세 | 필드 | 타입 | 설명 | |---|---|---| | `is_infringement` | bool | 후방호환용 임계 초과 매칭 여부. 법적 침해 확정 아님 | | `confidence` | float | 최상위 매칭 결합 유사도 원값(0~1). **화면 표시는 `review_summary` 사용 권장** | | `review_summary` | object | **저작권 탭 UI 직접 매핑** (§1 표 참조) | | `ai_generation` | object | AI 생성 의심도 상세. 미학습이면 `available=false`, 휴리스틱이면 `is_stub=true` | | `matches[]` | array | 매칭된 원본별 상세 (표절 시). 태그·케이스·근거 구간 포함 | | `matches[].tags[]` | array | 법령 태그. `role`: `primary`(주)/`secondary`(보조), `label_ko` 한글 표기 | | `matches[].case_id` | string | 39종 침해 케이스 ID (예: A6) | | `matches[].evidence_spans[]` | array | 본문 내 일치 구간 `{start, end, matched}` — 하이라이트용 | | `matches[].partial_signal` | object | 군집화 기반 부분 표절(인물만 교체 등) 분해 — 침해요소 DB 적재용 | | `ccl_basis` | string\|null | 사람이 읽는 판정 근거 문장 | | `engine_version` | string | 엔진 버전 | --- ## 4. 부가 엔드포인트 | Method | Path | 용도 | |---|---|---| | POST | `/v1/plagiarism/batch` | 배치 검사(≤500건). `202` + `job_id` 반환 → 아래 상태 조회 | | GET | `/v1/plagiarism/batch/{job_id}` | 배치 상태·결과 조회 | | POST | `/v1/summary` | 스토리 요약 (과제2 ②) | | GET | `/v1/taxonomy` | 10종 법령 태그 + 39 케이스 정의 (동일 라벨 공유용) | | GET | `/v1/health` | 엔진 상태·코퍼스 크기·버전 | --- ## 5. 에러 포맷 FastAPI 표준. HTTP 상태코드 + `detail`. ```json { "detail": "에러 메시지" } ``` | 코드 | 상황 | |---|---| | 400 | 잘못된 요청(빈 본문 등) | | 404 | 배치 job_id 없음 | | 422 | 스키마 검증 실패 | | 503 | 분류체계 미로딩 | --- ## 6. 연동 시 주의 1. **AI 생성 의심도는 확정값이 아님** — `available`/`is_stub`/`model_version`을 확인하고 사람 검토 우선순위로만 사용할 것. 출판 승인/거절 게이트로 쓰지 말 것(오탐 리스크). 2. **화면 값은 `review_summary` 사용** — `confidence`(원값)는 임베딩 성분 때문에 무관한 글도 높게 나오므로 직접 표시 금지. 독창성 환산은 오투오가 `review_summary`에서 완료해 제공. 3. **개인정보** — 실사용자 자서전 본문은 개인정보. 실서비스는 온프레미스(Docker) 납품으로 전환 예정. 개발 단계 REST 호출 시에도 테스트 데이터 사용 권장. 4. `compared_count` 는 현재 로딩된 코퍼스 크기. 실데이터 적재 후 실제 대조 건수로 표시됨.