o2o-plagiarism-ai/docs/API_SPEC_BAIKAL.md
hbyang 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

250 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 저작권 탐지 API 양식서 (오투오 → 바이칼)
> 나누구 앱 **저작권 탭** 연동용 API 계약. 본문 입력 → 표절 탐지 결과 + 저작권 탭
> 표시 항목을 반환한다. 본 문서 기준으로 UI를 연동하면 된다.
> 엔진: `o2o-plagiarism-api`
---
## 0. 기본 정보
| 항목 | 값 |
|---|---|
| Base URL (개발/통합 테스트) | `https://plagiarism.o2o.kr` |
| 프로토콜 | HTTPS, `Content-Type: application/json` (UTF-8) |
| 인증 | 운영 설정 시 `X-API-Key` 헤더 사용 |
| 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
},
"legal_context": {
"work_type": "literary",
"access_evidence": null,
"protected_expression_reviewed": false,
"rights_verified": false
}
}
```
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| `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이면 서버 설정 |
| `legal_context` | object | | 사람이 확인한 접근 가능성·창작성·권리관계. 없으면 미확인으로 처리 |
### 응답 (저작권 탭에 표시되는 "깨끗한 글" 예시)
```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": 37891,
"has_suspicion": false,
"ai_suspicion_level": "low"
},
"ai_generation": {
"suspicion_level": "low",
"score": 0.02,
"is_stub": false,
"available": true,
"model_version": "hgb-nolen-kf-ko-v1-Qwen3.8-27B-gpt-4.1-mini-gpt-4o-mini-Korean-autobiography-v2-auroc0.997",
"note": "Qwen·GPT 한국어 자서전 범위의 검토 우선순위 점수이며 AI 작성 확정 판정이 아님"
},
"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": 37891,
"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=true`, `is_stub=false` |
| `matches[]` | array | 매칭된 원본별 상세 (표절 시). 태그·케이스·근거 구간 포함 |
| `matches[].tags[]` | array | 법령 태그. `role`: `primary`(주)/`secondary`(보조), `label_ko` 한글 표기 |
| `matches[].case_id` | string | 39종 침해 케이스 ID. `case_candidates[0]` 과 같다 |
| `matches[].case_candidates[]` | array | 태그 동점 케이스 **전부**. 태그만으로는 1:1로 좁혀지지 않으므로(A1·A2·A3·A4·A5·A6·A15 는 태그가 동일) 원본의 종류로 사람이 확정한다 |
| `matches[].case_candidates[].handling` | string | `technical_detection`(v1.3 ●) / `terms_or_report`(○) |
| `matches[].case_candidates[].representative_precedents[]` | array | v1.3 IX장 총괄표의 대표판례 사건번호 |
| `matches[].case_candidates[].precedents_without_source[]` | array | 대표판례이나 적재본에 없어 출처 제시 불가. `docs/PRECEDENT_SOURCE_GAP.md` 참조 |
| `matches[].evidence_spans[]` | array | 본문 내 일치 구간 `{start, end, matched}` — 하이라이트용 |
| `matches[].partial_signal` | object | 군집화 기반 부분 표절(인물만 교체 등) 분해 — 침해요소 DB 적재용 |
| `ccl_basis` | string\|null | 사람이 읽는 판정 근거 문장 |
| `legal_risk` | object\|null | 판례 기반 위험도, 사건번호, A/B/C 검토 등급과 판단 근거 |
| `score_semantics` | object\|null | 검색 점수·임계값·일치 범위의 의미 |
| `has_similarity_match` | bool\|null | 등록 코퍼스 유사 원문 확인 여부 |
| `corpus_scope_note` | 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/precedents` | 전체 판례 검색·등급·저작물 유형 필터 |
| GET | `/v1/taxonomy` | 10종 법령 태그 + 39 케이스 정의 + 케이스별 대표판례 (동일 라벨 공유용) |
| GET | `/v1/health` | 엔진 상태·코퍼스 크기·버전 |
### 맞춤 요약 옵션
`POST /v1/summary``detail`(`brief|standard|detailed`), `emphasis`(최대 10개),
`ratio`, `max_sentences`, `use_abstractive`를 받는다. `ratio`를 지정하면 `detail`보다
우선한다.
### 판례 조회
`GET /v1/precedents``q`, `grade`(`A|B|C|unreviewed`), `work_type`, `offset`,
`limit` 쿼리를 지원한다. 운영 판례 545건 전체가 검색·인용 후보이며 A/B/C 등급은
제외 조건이 아니라 검토 품질과 직접성에 따른 우선순위다.
### 상태 확인 확장
`GET /v1/health`에는 `corpus_documents`, `index_backend`, `ai_model_ready`,
`precedent_count`가 추가되었다.
---
## 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` 는 현재 로딩된 검색 세그먼트 수다. 문서 수와 혼동하지 않는다.
5. 현재 운영 코퍼스는 612개 문서, 37,891개 세그먼트이며 판례는 545건이다. 데이터
증분 적재 시 수치는 달라질 수 있으므로 화면에서는 API 반환값을 그대로 사용한다.