8.4 KiB
8.4 KiB
저작권 탐지 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 필드 매핑 (핵심)
나누구 저작권 탭의 각 표시 항목은 아래 필드에서 그대로 읽으면 된다. 별도 계산 불필요
— 독창성 환산(점수 변환)까지 오투오가 완료해 review_summary로 제공한다.
| 화면 표시 | 예시 | API 필드 |
|---|---|---|
| 독창성 98% | 98 | review_summary.originality_percent |
| 저작권 · 유사도 2% | 2 | review_summary.similarity_percent |
| 유사 문장 0건 | 0 | review_summary.similar_sentence_count |
| 나누구 에피소드 3.5만 건과 대조 | 35000 | review_summary.compared_count |
| 표절 의심 구간 없음 | false | review_summary.has_suspicion |
| AI 생성 의심도 낮음 | low | review_summary.ai_suspicion_level |
ai_suspicion_level값 매핑:low=낮음,medium=중간,high=높음,unknown=미학습 또는 채점 불가. 학습 모델이 없으면 점수를 만들지 않고ai_generation.available=false,score=null을 반환합니다. UI는 지금 그대로 붙여두면 되고, 정식 구현 시 값만 실제로 바뀝니다.
2. 표절 탐지 — POST /v1/plagiarism/detect
본문 1건을 검사한다.
요청
{
"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이면 서버 설정 |
응답 (저작권 탭에 표시되는 "깨끗한 글" 예시)
{
"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가 채워짐)
{
"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 | 엔진 버전 |
3. 부가 엔드포인트
| 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 |
엔진 상태·코퍼스 크기·버전 |
4. 에러 포맷
FastAPI 표준. HTTP 상태코드 + detail.
{ "detail": "에러 메시지" }
| 코드 | 상황 |
|---|---|
| 400 | 잘못된 요청(빈 본문 등) |
| 404 | 배치 job_id 없음 |
| 422 | 스키마 검증 실패 |
| 503 | 분류체계 미로딩 |
5. 연동 시 주의
- AI 생성 의심도는 확정값이 아님 —
available/is_stub/model_version을 확인하고 사람 검토 우선순위로만 사용할 것. 출판 승인/거절 게이트로 쓰지 말 것(오탐 리스크). - 화면 값은
review_summary사용 —confidence(원값)는 임베딩 성분 때문에 무관한 글도 높게 나오므로 직접 표시 금지. 독창성 환산은 오투오가review_summary에서 완료해 제공. - 개인정보 — 실사용자 자서전 본문은 개인정보. 실서비스는 온프레미스(Docker) 납품으로 전환 예정. 개발 단계 REST 호출 시에도 테스트 데이터 사용 권장.
compared_count는 현재 로딩된 코퍼스 크기. 실데이터 적재 후 실제 대조 건수로 표시됨.