Image rights / copyright detection system: SQLite store, HTTP app, search integrations (Naver, Google Custom Search, Google Cloud Vision web detection), image analysis (fingerprints, face/person detection, evidence enrichment, risk scoring), an admin/review layer, governance and retention policies, batch jobs, and a browser-based operator GUI. This baseline incorporates a full code-review remediation pass (46 fixes; 358 tests passing). Highlights: CRITICAL - Prevent evidence cascade-delete during the schema-constraint migration by disabling FK enforcement around the table rebuild. Security - Sandbox served media (neutralize stored XSS from uploaded/collected SVGs) via CSP + nosniff on the untrusted media routes. - Strip embedded EXIF/GPS from external image derivatives before they are sent to third-party APIs. - Return a clean 404 (not an uncaught StopIteration) for PATCH on an unknown provider. Correctness - LLM-summary failures no longer add +30 to the risk score. - Decode only explicit JS escapes so Korean image URLs are not mangled. - Consume search quota only after a successful request. - Naver/Google adapters map responses inside the failure boundary, so a malformed response degrades to evidence instead of crashing enrichment. - Domain-aware provider attribution; face-box IoU de-duplication; count searches (not result items); per-box crop isolation; clamp evidence confidence and Google CSE num; real submittedEpoch; and more. Robustness - Offline LLM connect fast-fails (short connect timeout) so seed/reload requests are not stalled; full read timeout preserved for generation. - Malformed numeric env vars fall back to defaults instead of crashing startup. Performance - Per-submission evidence reads (no full-table scan per rescore), audit-log LIMIT, lazy active-store lookup, hoisted timestamps. Tests - ~24 regression tests added pinning the above fixes. Runtime data (data/, outputs/, *.sqlite3, *.log), secrets (.env), and node_modules are gitignored.
773 lines
25 KiB
HTML
773 lines
25 KiB
HTML
<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Copyrighter AI/ML 사용 설명서</title>
|
|
<style>
|
|
:root {
|
|
--bg: #f4f1ea;
|
|
--panel: #ffffff;
|
|
--panel-soft: #fbfaf6;
|
|
--ink: #172124;
|
|
--muted: #5f6b6f;
|
|
--line: #d7ccbd;
|
|
--accent: #24667a;
|
|
--green: #28734f;
|
|
--red: #a13d35;
|
|
--amber: #916300;
|
|
--blue-soft: #edf7fb;
|
|
--green-soft: #ecf8f1;
|
|
--amber-soft: #fff7e2;
|
|
--red-soft: #fff0ed;
|
|
--shadow: 0 18px 42px rgba(23, 33, 36, 0.12);
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
font-family: "Segoe UI", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
|
|
line-height: 1.58;
|
|
}
|
|
|
|
a {
|
|
color: inherit;
|
|
}
|
|
|
|
.shell {
|
|
width: min(1180px, calc(100vw - 32px));
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.hero {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 0.95fr) minmax(420px, 1.05fr);
|
|
gap: 30px;
|
|
align-items: center;
|
|
min-height: 84vh;
|
|
padding: 42px 0 26px;
|
|
}
|
|
|
|
.eyebrow {
|
|
margin: 0 0 10px;
|
|
color: var(--accent);
|
|
font-size: 12px;
|
|
font-weight: 900;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3 {
|
|
margin: 0;
|
|
line-height: 1.18;
|
|
}
|
|
|
|
h1 {
|
|
max-width: 760px;
|
|
font-size: clamp(38px, 5.3vw, 70px);
|
|
}
|
|
|
|
h2 {
|
|
font-size: clamp(28px, 3.1vw, 42px);
|
|
}
|
|
|
|
h3 {
|
|
font-size: 18px;
|
|
}
|
|
|
|
p {
|
|
margin: 10px 0 0;
|
|
}
|
|
|
|
.lead {
|
|
max-width: 670px;
|
|
margin-top: 18px;
|
|
color: var(--muted);
|
|
font-size: 18px;
|
|
}
|
|
|
|
.hero-card,
|
|
.panel,
|
|
.image-card,
|
|
.claim-card,
|
|
.metric-card {
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
background: var(--panel);
|
|
}
|
|
|
|
.hero-card {
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.hero-card img,
|
|
.image-card img {
|
|
display: block;
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
.caption {
|
|
padding: 12px 14px;
|
|
color: var(--muted);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.answer-strip {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 14px;
|
|
margin: 0 0 32px;
|
|
}
|
|
|
|
.verdict,
|
|
.warning {
|
|
padding: 22px;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.verdict {
|
|
border: 1px solid #9ec8b0;
|
|
background: var(--green-soft);
|
|
}
|
|
|
|
.warning {
|
|
border: 1px solid #e5c08a;
|
|
background: var(--amber-soft);
|
|
}
|
|
|
|
.verdict strong,
|
|
.warning strong {
|
|
display: block;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.verdict strong {
|
|
color: var(--green);
|
|
font-size: 28px;
|
|
}
|
|
|
|
.warning strong {
|
|
color: var(--amber);
|
|
font-size: 20px;
|
|
}
|
|
|
|
section {
|
|
padding: 46px 0;
|
|
}
|
|
|
|
.section-head {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 0.72fr) minmax(320px, 0.28fr);
|
|
gap: 22px;
|
|
align-items: end;
|
|
margin-bottom: 18px;
|
|
}
|
|
|
|
.section-head p,
|
|
.panel p,
|
|
.claim-card p,
|
|
.metric-card p,
|
|
.plain-list li {
|
|
color: var(--muted);
|
|
}
|
|
|
|
.claim-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
gap: 12px;
|
|
}
|
|
|
|
.claim-card,
|
|
.metric-card,
|
|
.panel {
|
|
padding: 16px;
|
|
}
|
|
|
|
.claim-card strong {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
min-height: 24px;
|
|
margin-bottom: 12px;
|
|
padding: 3px 8px;
|
|
border: 1px solid var(--line);
|
|
border-radius: 999px;
|
|
background: var(--panel-soft);
|
|
color: var(--muted);
|
|
font-size: 12px;
|
|
font-weight: 800;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tag.ai {
|
|
border-color: #b9cfdb;
|
|
background: var(--blue-soft);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.tag.ml {
|
|
border-color: #a6d4b7;
|
|
background: var(--green-soft);
|
|
color: var(--green);
|
|
}
|
|
|
|
.tag.guard {
|
|
border-color: #e5c08a;
|
|
background: var(--amber-soft);
|
|
color: var(--amber);
|
|
}
|
|
|
|
.tag.rule {
|
|
border-color: #c4b6a2;
|
|
background: #f6efe3;
|
|
color: #594b36;
|
|
}
|
|
|
|
.two-col {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
gap: 16px;
|
|
}
|
|
|
|
.three-col {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 12px;
|
|
}
|
|
|
|
.metric-card strong {
|
|
display: block;
|
|
color: var(--accent);
|
|
font-size: 28px;
|
|
}
|
|
|
|
.mermaid-wrap {
|
|
padding: 16px;
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
background: #ffffff;
|
|
overflow: auto;
|
|
}
|
|
|
|
.evidence-stack {
|
|
display: grid;
|
|
gap: 12px;
|
|
}
|
|
|
|
.evidence-row {
|
|
display: grid;
|
|
grid-template-columns: 180px minmax(0, 1fr) 170px;
|
|
gap: 12px;
|
|
align-items: start;
|
|
padding: 14px;
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
background: var(--panel);
|
|
}
|
|
|
|
.evidence-row strong,
|
|
.evidence-row span {
|
|
min-width: 0;
|
|
}
|
|
|
|
.evidence-row span {
|
|
color: var(--muted);
|
|
}
|
|
|
|
.score-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
overflow: hidden;
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
background: var(--panel);
|
|
}
|
|
|
|
.score-table th,
|
|
.score-table td {
|
|
padding: 12px;
|
|
border-bottom: 1px solid var(--line);
|
|
text-align: left;
|
|
vertical-align: top;
|
|
}
|
|
|
|
.score-table th {
|
|
background: #efe9dd;
|
|
color: #3f4b4d;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.score-table td {
|
|
color: var(--muted);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.score-table tr:last-child td {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.image-grid,
|
|
.language-box {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 14px;
|
|
}
|
|
|
|
.do,
|
|
.dont {
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.do {
|
|
border: 1px solid #9ec8b0;
|
|
background: var(--green-soft);
|
|
}
|
|
|
|
.dont {
|
|
border: 1px solid #e3aaa4;
|
|
background: var(--red-soft);
|
|
}
|
|
|
|
.plain-list {
|
|
margin: 12px 0 0;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.plain-list li + li {
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.code-list {
|
|
display: grid;
|
|
gap: 8px;
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
.code-list li {
|
|
padding: 10px 12px;
|
|
border: 1px solid var(--line);
|
|
border-radius: 8px;
|
|
background: var(--panel-soft);
|
|
font-family: Consolas, "Cascadia Mono", monospace;
|
|
font-size: 13px;
|
|
}
|
|
|
|
footer {
|
|
padding: 34px 0 52px;
|
|
color: var(--muted);
|
|
font-size: 13px;
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
.hero,
|
|
.answer-strip,
|
|
.section-head,
|
|
.two-col,
|
|
.image-grid,
|
|
.language-box {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.claim-grid,
|
|
.three-col {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
|
|
.evidence-row {
|
|
grid-template-columns: 150px minmax(0, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 620px) {
|
|
.claim-grid,
|
|
.three-col,
|
|
.evidence-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
section {
|
|
padding: 34px 0;
|
|
}
|
|
|
|
.score-table {
|
|
display: block;
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
</style>
|
|
<script type="module">
|
|
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
mermaid.initialize({
|
|
startOnLoad: true,
|
|
theme: "base",
|
|
themeVariables: {
|
|
primaryColor: "#edf7fb",
|
|
primaryTextColor: "#172124",
|
|
primaryBorderColor: "#9eb8c4",
|
|
lineColor: "#5f6b6f",
|
|
secondaryColor: "#ecf8f1",
|
|
tertiaryColor: "#fff7e2",
|
|
fontFamily: "Segoe UI, Malgun Gothic, sans-serif"
|
|
}
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<main class="shell">
|
|
<section class="hero">
|
|
<div>
|
|
<p class="eyebrow">AI/ML usage explainer</p>
|
|
<h1>Copyrighter의 AI/ML은 판정 자동화가 아니라 근거 자동화입니다.</h1>
|
|
<p class="lead">
|
|
시스템은 제출 이미지를 분석해 유사 이미지, 웹 출처, 인물 존재 신호, 기준 DB 유사도, 검색 증거, LLM 요약을 만듭니다.
|
|
최종 저작권 위험 판정은 운영자가 하며, AI/ML 출력은 그 판단을 빠르게 만드는 검토 근거입니다.
|
|
</p>
|
|
</div>
|
|
<figure class="hero-card">
|
|
<img src="../web/operator-gui/pitch-assets/case-review.png" alt="Copyrighter 케이스 심사 화면">
|
|
<figcaption class="caption">케이스 심사 화면은 위험 점수, 상위 근거, 검색 증거, 요약, 운영자 판정을 한 흐름에 배치합니다.</figcaption>
|
|
</figure>
|
|
</section>
|
|
|
|
<div class="answer-strip">
|
|
<div class="verdict">
|
|
<strong>AI/ML 사용이라고 말할 수 있다.</strong>
|
|
<span>컴퓨터 비전 ML, 로컬 생성형 AI, 얼굴/인물 감지, 이미지 유사도 계산이 실제 처리 흐름에 포함되어 있습니다.</span>
|
|
</div>
|
|
<div class="warning">
|
|
<strong>정확한 표현</strong>
|
|
<span>“AI가 침해 여부를 확정한다”가 아니라 “AI/ML이 출처 기반 증거와 위험 triage를 생성하고, 운영자가 최종 판단한다”입니다.</span>
|
|
</div>
|
|
</div>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Definitions</p>
|
|
<h2>이 문서에서 AI, ML, 알고리즘은 서로 다른 역할을 합니다.</h2>
|
|
</div>
|
|
<p>혼동을 줄이려면 “어떤 기술이 무엇을 보고, 무엇을 산출하며, 그 산출물이 점수에 어떻게 반영되는지”를 분리해야 합니다.</p>
|
|
</div>
|
|
|
|
<div class="claim-grid">
|
|
<article class="claim-card">
|
|
<span class="tag ml">ML</span>
|
|
<strong>Google Cloud Vision Web Detection</strong>
|
|
<p>이미지에서 웹 엔티티, 동일 이미지, 부분 매칭, 유사 이미지, 출처 페이지 후보를 반환합니다. 외부 ML 서비스가 만든 탐지 결과입니다.</p>
|
|
</article>
|
|
<article class="claim-card">
|
|
<span class="tag ai">Generative AI</span>
|
|
<strong>Ollama 로컬 LLM 요약</strong>
|
|
<p>저장된 evidence만 입력으로 받아 운영자용 요약을 생성합니다. 새 사실을 만들거나 최종 판정을 내리지 않도록 제한합니다.</p>
|
|
</article>
|
|
<article class="claim-card">
|
|
<span class="tag ml">Classical CV</span>
|
|
<strong>얼굴/인물 존재 감지</strong>
|
|
<p>OpenCV Haar cascade로 얼굴 박스 존재를 탐지합니다. 동일인 식별, 얼굴 임베딩, 신원 추정은 수행하지 않습니다.</p>
|
|
</article>
|
|
<article class="claim-card">
|
|
<span class="tag rule">Algorithm</span>
|
|
<strong>SHA / pHash 이미지 지문</strong>
|
|
<p>학습 모델은 아니지만 이미지 내용의 지문을 만들고 해밍 거리로 유사도를 계산해 기준 DB 및 검색 결과 이미지와 비교합니다.</p>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Operating pipeline</p>
|
|
<h2>한 장의 제출 이미지는 evidence 묶음으로 변환됩니다.</h2>
|
|
</div>
|
|
<p>위험 점수는 LLM이 직접 만든 값이 아니라, 각 evidence의 유형과 신뢰도에 규칙을 적용해 계산한 triage 점수입니다.</p>
|
|
</div>
|
|
|
|
<div class="mermaid-wrap">
|
|
<pre class="mermaid">
|
|
flowchart LR
|
|
A[제출 이미지] --> B[로컬 전처리]
|
|
B --> C[SHA / pHash 지문 생성]
|
|
B --> D[얼굴·인물 존재 감지]
|
|
B --> E[Google Vision Web Detection]
|
|
E --> F[웹 엔티티·동일 이미지·부분 매칭·출처 페이지]
|
|
F --> G[Naver 텍스트 검색 보강]
|
|
F --> H[레거시 Google 맞춤 검색<br/>비활성 가능]
|
|
C --> I[기준 DB 및 검색 결과 이미지 유사도 비교]
|
|
D --> J[로컬 인물 존재 evidence]
|
|
F --> K[Google evidence]
|
|
G --> L[Naver evidence]
|
|
H --> L
|
|
I --> M[유사도 evidence]
|
|
J --> N[규칙 기반 위험 점수]
|
|
K --> N
|
|
L --> N
|
|
M --> N
|
|
K --> O[Ollama LLM 요약]
|
|
L --> O
|
|
M --> O
|
|
O --> P[출처 연결 요약 evidence]
|
|
N --> Q[운영자 검토]
|
|
P --> Q
|
|
Q --> R[승인 / 보류 / 반려]
|
|
|
|
classDef ai fill:#edf7fb,stroke:#24667a,color:#172124;
|
|
classDef cv fill:#ecf8f1,stroke:#28734f,color:#172124;
|
|
classDef rule fill:#fff7e2,stroke:#916300,color:#172124;
|
|
classDef human fill:#fff0ed,stroke:#a13d35,color:#172124;
|
|
class E,O ai;
|
|
class C,D,I cv;
|
|
class N rule;
|
|
class Q,R human;
|
|
</pre>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">What comes out</p>
|
|
<h2>각 기술은 서로 다른 결과물을 만들고, UI는 이를 한 줄의 판단 근거로 모읍니다.</h2>
|
|
</div>
|
|
<p>이 구분이 중요합니다. “신뢰도”는 하나의 전역 AI 확률값이 아니라 evidence별 confidence, 유사도, 매칭 유형, 규칙 점수의 조합입니다.</p>
|
|
</div>
|
|
|
|
<div class="evidence-stack">
|
|
<div class="evidence-row">
|
|
<strong>Google Vision</strong>
|
|
<span>웹 엔티티, full/partial/visual image match, matching page, weak label을 생성합니다.</span>
|
|
<span>confidence는 Google score 또는 fallback confidence에서 옵니다.</span>
|
|
</div>
|
|
<div class="evidence-row">
|
|
<strong>Naver 검색</strong>
|
|
<span>Google/기준 DB에서 나온 이름, 페이지 제목, 라벨을 텍스트 쿼리로 확장해 블로그/웹문서 근거를 모읍니다.</span>
|
|
<span>promoted 결과만 위험 점수에 직접 기여합니다.</span>
|
|
</div>
|
|
<div class="evidence-row">
|
|
<strong>pHash 유사도</strong>
|
|
<span>64비트 perceptual hash의 해밍 거리로 0.0~1.0 유사도를 계산합니다.</span>
|
|
<span>0.9 이상이면 강한 동일/유사 이미지 신호로 취급합니다.</span>
|
|
</div>
|
|
<div class="evidence-row">
|
|
<strong>얼굴/인물 감지</strong>
|
|
<span>얼굴 또는 인물이 있는지 presence-only 신호를 제공합니다.</span>
|
|
<span>신원 식별 confidence가 아니라 위험 검토 필요성 신호입니다.</span>
|
|
</div>
|
|
<div class="evidence-row">
|
|
<strong>Ollama LLM 요약</strong>
|
|
<span>기존 evidence의 출처, 이유, confidence, URL만 보고 내부 운영자용 요약을 생성합니다.</span>
|
|
<span>위험 점수에는 직접 가산되지 않습니다.</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="two-col">
|
|
<div class="panel">
|
|
<p class="eyebrow">Score and confidence</p>
|
|
<h2>위험 점수는 AI의 “확률”이 아니라 규칙 기반 triage 점수입니다.</h2>
|
|
<p>
|
|
evidence에는 confidence가 붙지만, 최종 riskScore는 `RiskScorer`가 evidence 유형별 가중치를 더해 0~100으로 제한한 값입니다.
|
|
따라서 “100점 = 100% 침해 확률”이 아니라 “검토 우선순위가 매우 높음”입니다.
|
|
</p>
|
|
</div>
|
|
<div class="panel">
|
|
<p class="eyebrow">Band</p>
|
|
<h2>점수는 운영 큐 정렬을 위한 구간으로 변환됩니다.</h2>
|
|
<ul class="plain-list">
|
|
<li>70점 이상: 높음</li>
|
|
<li>30점 이상 70점 미만: 중간</li>
|
|
<li>30점 미만: 낮음</li>
|
|
<li>LLM 요약 evidence는 점수 가산에서 제외됩니다.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<table class="score-table" aria-label="위험 점수 계산 규칙 요약">
|
|
<thead>
|
|
<tr>
|
|
<th>근거 유형</th>
|
|
<th>점수 반영 방식</th>
|
|
<th>의미</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>pHash 유사도</td>
|
|
<td>similarity 0.9 이상이면 +80, 그 외 의미 있는 지문 근거는 +30</td>
|
|
<td>기준 DB 또는 검색 결과 이미지와 시각적으로 매우 가깝다는 신호</td>
|
|
</tr>
|
|
<tr>
|
|
<td>얼굴/인물 존재</td>
|
|
<td>존재 신호가 있으면 +35</td>
|
|
<td>초상권/인물 이미지 검토가 필요할 수 있다는 신호</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Google full match</td>
|
|
<td>동일 이미지 매칭은 +45</td>
|
|
<td>웹에 같은 이미지가 존재한다는 강한 출처 후보</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Google partial/page match</td>
|
|
<td>부분 이미지 또는 페이지 매칭은 +35</td>
|
|
<td>일부 요소 또는 출처 페이지가 제출 이미지와 관련될 가능성</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Google visual match</td>
|
|
<td>시각적 유사 이미지는 +10</td>
|
|
<td>약한 참고 신호이며 단독으로 강한 판정 근거가 되지 않음</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Naver promoted 검색 결과</td>
|
|
<td>round(50 * confidence)</td>
|
|
<td>검색 결과가 기준 후보로 승격될 만큼 관련성이 있다고 본 경우</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Ollama LLM 요약</td>
|
|
<td>0점</td>
|
|
<td>판정 점수가 아니라 사람이 읽기 쉬운 출처 연결 설명</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Trust boundaries</p>
|
|
<h2>신뢰도는 단계별로 다르게 해석해야 합니다.</h2>
|
|
</div>
|
|
<p>설명 자료에서는 “AI 신뢰도” 하나로 뭉뚱그리지 말고 아래처럼 말하는 편이 정확합니다.</p>
|
|
</div>
|
|
|
|
<div class="three-col">
|
|
<article class="metric-card">
|
|
<strong>Evidence confidence</strong>
|
|
<p>Google score, fallback confidence, 검색 승격 confidence처럼 개별 근거에 붙는 값입니다.</p>
|
|
</article>
|
|
<article class="metric-card">
|
|
<strong>Similarity</strong>
|
|
<p>pHash 거리에서 나온 이미지 유사도입니다. ML 확률이 아니라 지문 거리 기반 수치입니다.</p>
|
|
</article>
|
|
<article class="metric-card">
|
|
<strong>Risk score</strong>
|
|
<p>여러 근거를 규칙으로 합산한 운영 우선순위 점수입니다. 법적 침해 확률이 아닙니다.</p>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="two-col">
|
|
<div class="panel">
|
|
<p class="eyebrow">LLM guardrail</p>
|
|
<h2>LLM은 근거를 요약할 뿐, 새 결론을 만들지 못하게 설계되어 있습니다.</h2>
|
|
<p>
|
|
프롬프트는 “제공된 source evidence만 요약하라”, “최종 결정을 내리지 말라”, “근거 없는 주장을 추가하지 말라”로 제한됩니다.
|
|
요약 evidence에는 source URL 또는 source evidence id가 연결됩니다.
|
|
</p>
|
|
</div>
|
|
<div class="mermaid-wrap">
|
|
<pre class="mermaid">
|
|
sequenceDiagram
|
|
participant DB as Evidence DB
|
|
participant LLM as Ollama 로컬 LLM
|
|
participant UI as 운영 콘솔
|
|
participant Human as 운영자
|
|
|
|
DB->>LLM: fingerprint, face, google, naver evidence 전달
|
|
LLM->>DB: 출처 연결 요약 evidence 저장
|
|
DB->>UI: 원문 evidence + 요약 evidence 표시
|
|
Human->>UI: 증거 사용/미사용 선택
|
|
Human->>UI: 승인/보류/반려 최종 판정
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Visual proof</p>
|
|
<h2>운영 화면은 AI/ML 결과가 어떻게 사람이 검토할 수 있는 근거로 바뀌는지 보여줍니다.</h2>
|
|
</div>
|
|
<p>시연에서는 “AI가 판정했다”가 아니라 “AI/ML이 근거를 정리했고 운영자가 판정한다”는 화면 흐름을 보여주는 것이 좋습니다.</p>
|
|
</div>
|
|
|
|
<div class="image-grid">
|
|
<figure class="image-card">
|
|
<img src="../web/operator-gui/pitch-assets/evidence-search.png" alt="검색 증거 화면">
|
|
<figcaption class="caption">검색 증거: 쿼리, 출처 URL, 이미지, 매칭 유형이 함께 남아 추적 가능한 검토 근거가 됩니다.</figcaption>
|
|
</figure>
|
|
<figure class="image-card">
|
|
<img src="../web/operator-gui/pitch-assets/provider-controls.png" alt="외부 검색 tool 활용 화면">
|
|
<figcaption class="caption">외부 검색 tool 활용: Google, Naver, Ollama의 활성 상태, 실패 상태, 사용량을 운영자가 확인합니다.</figcaption>
|
|
</figure>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Recommended wording</p>
|
|
<h2>강조 문구는 기술의 힘과 판정 책임의 경계를 함께 담아야 합니다.</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="language-box">
|
|
<div class="do">
|
|
<h3>추천 표현</h3>
|
|
<p>Copyrighter는 컴퓨터 비전 ML, 이미지 지문 유사도, 검색 증거 수집, 로컬 LLM 요약을 결합해 이미지 저작권 위험 검토 근거를 자동 생성합니다.</p>
|
|
<p>위험 점수는 AI가 내린 법적 결론이 아니라 evidence confidence, 매칭 유형, 이미지 유사도에 기반한 운영 triage 점수입니다.</p>
|
|
<p>최종 승인, 보류, 반려는 운영자가 수행하며 모든 근거는 출처와 함께 보존됩니다.</p>
|
|
</div>
|
|
<div class="dont">
|
|
<h3>피해야 할 표현</h3>
|
|
<p>AI가 저작권 침해 여부를 자동 판정합니다.</p>
|
|
<p>LLM이 원작자, 유명인, 침해 여부를 단독으로 확정합니다.</p>
|
|
<p>위험 점수 100은 침해 확률 100%를 의미합니다.</p>
|
|
<p>Naver에 이미지를 업로드해 역검색합니다.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-head">
|
|
<div>
|
|
<p class="eyebrow">Code evidence</p>
|
|
<h2>설명서의 근거가 되는 구현 지점입니다.</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<ul class="code-list">
|
|
<li>src/rights_filter/integrations/cloud_vision_web_detection.py - Google Cloud Vision Web Detection 호출 및 evidence 매핑</li>
|
|
<li>src/rights_filter/analysis/llm_assistance.py - Ollama Generate API 기반 source-linked LLM 요약</li>
|
|
<li>src/rights_filter/analysis/fingerprints.py - SHA 및 pHash 이미지 지문, 해밍 거리 기반 유사도</li>
|
|
<li>src/rights_filter/analysis/face_person_detection.py - OpenCV Haar cascade 기반 얼굴/인물 존재 감지</li>
|
|
<li>src/rights_filter/analysis/risk_scoring.py - evidence 유형별 규칙 기반 위험 점수 산정</li>
|
|
<li>src/rights_filter/server/sqlite_store.py - evidence 저장, 외부 검색 tool 활용 상태, LLM 요약 자동 생성</li>
|
|
<li>docs/operations/image-rights-risk-filter.md - 외부 API, LLM, 데이터 경계 운영 정책</li>
|
|
</ul>
|
|
</section>
|
|
</main>
|
|
|
|
<footer class="shell">
|
|
Copyrighter AI/ML usage explainer. AI/ML 출력은 내부 검수 근거이며 최종 판정은 운영자가 수행합니다.
|
|
</footer>
|
|
</body>
|
|
</html>
|