reports 수정 및 script 수정 .
This commit is contained in:
parent
6b27fff509
commit
1e56bdf1c0
BIN
reports/침해판별_결과보고.xlsx
Normal file
BIN
reports/침해판별_결과보고.xlsx
Normal file
Binary file not shown.
Binary file not shown.
@ -27,22 +27,33 @@ TAG_LABELS = {
|
||||
|
||||
RESULT_COLUMNS = [
|
||||
("doc_id", "doc_id", 28),
|
||||
("id", "id (제출자 이메일)", 26),
|
||||
("원문 자서전 제목", "원문 자서전 제목", 22),
|
||||
("가명 제목", "가명 제목", 22),
|
||||
("원천 구분", "원천 구분", 14),
|
||||
("침해 여부", "침해 여부", 12),
|
||||
("결합유사도", "결합유사도", 11),
|
||||
("매칭 상대 제목", "매칭 상대 제목", 22),
|
||||
("매칭 상대 id", "매칭 상대 id (이메일)", 26),
|
||||
("동일 이메일", "동일 이메일", 12),
|
||||
("evidence 스팬 수", "근거 스팬 수", 12),
|
||||
("union_coverage", "근거 커버리지", 12),
|
||||
]
|
||||
|
||||
DETAIL_COLUMNS = [
|
||||
("doc_id", "doc_id", 28),
|
||||
("id", "id (제출자 이메일)", 26),
|
||||
("원문 자서전 제목", "원문 자서전 제목", 22),
|
||||
("원문 에피소드 제목", "원문 에피소드 제목", 26),
|
||||
("원본 엑셀 행", "원본 엑셀 행", 12),
|
||||
("가명 제목", "가명 제목", 22),
|
||||
("원천 구분", "원천 구분", 14),
|
||||
("결합유사도", "결합유사도", 11),
|
||||
("매칭 상대 제목", "매칭 상대 제목", 22),
|
||||
("매칭 상대 doc", "매칭 상대 doc", 28),
|
||||
("매칭 상대 id", "매칭 상대 id (이메일)", 26),
|
||||
("매칭 상대 원문 제목", "매칭 상대 원문 제목", 22),
|
||||
("동일 이메일", "동일 이메일", 12),
|
||||
("evidence 스팬 수", "근거 스팬 수", 12),
|
||||
("union_coverage", "근거 커버리지", 12),
|
||||
("text 점수", "표현 유사도", 11),
|
||||
@ -483,6 +494,35 @@ def build_sweep_sheet(wb: Workbook, sweep: list[dict], rows: list[dict],
|
||||
sheet.column_dimensions[get_column_letter(index)].width = width
|
||||
|
||||
|
||||
def load_hash_map(path: Path) -> dict:
|
||||
"""segment_id → 원문 정보. 가명 해시를 제출 이메일·원문 제목으로 되돌린다."""
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def enrich_with_identity(rows: list[dict], hash_map: dict) -> None:
|
||||
"""각 행에 제출자 이메일과 원문 제목을 붙인다.
|
||||
|
||||
매칭 상대는 세그먼트 ID가 비어 있는 경우가 있어 문서 단위로도 찾도록
|
||||
doc → 원문 색인을 함께 만든다. 생활수기는 익명화된 상태로 수령해 이메일이
|
||||
없으므로 '-' 로 남긴다.
|
||||
"""
|
||||
by_doc: dict[str, dict] = {}
|
||||
for info in hash_map.values():
|
||||
by_doc.setdefault(info["doc"], info)
|
||||
for row in rows:
|
||||
mine = hash_map.get(row.get("query_segment_id") or "") or by_doc.get(row.get("doc_id"))
|
||||
peer = hash_map.get(row.get("매칭 상대 segment") or "") or by_doc.get(row.get("매칭 상대 doc"))
|
||||
row["id"] = (mine or {}).get("email") or "-"
|
||||
row["원문 자서전 제목"] = (mine or {}).get("book") or "-"
|
||||
row["원문 에피소드 제목"] = (mine or {}).get("episode") or "-"
|
||||
row["원본 엑셀 행"] = (mine or {}).get("row")
|
||||
row["매칭 상대 id"] = (peer or {}).get("email") or "-"
|
||||
row["매칭 상대 원문 제목"] = (peer or {}).get("book") or "-"
|
||||
row["동일 이메일"] = (
|
||||
"예" if row["id"] != "-" and row["id"] == row["매칭 상대 id"] else "아니오"
|
||||
)
|
||||
|
||||
|
||||
SCORE_MIN = 0.65
|
||||
SPAN_MIN = 35
|
||||
COVERAGE_MIN = 0.30
|
||||
@ -516,6 +556,7 @@ def judgment_reasons(row: dict, longest_span: int) -> list[str]:
|
||||
|
||||
|
||||
EXCERPT_COLUMNS = [
|
||||
("id (제출자 이메일)", 26), ("매칭 상대 id (이메일)", 26), ("동일 이메일", 12),
|
||||
("가명 제목", 20), ("침해 여부", 12), ("판정 사유", 26), ("매칭 상대 제목", 20),
|
||||
("결합유사도", 11), ("일치 구간 길이", 13),
|
||||
("일치 구간 (똑같은 문장)", 70), ("검사 대상 원문", 70), ("매칭 상대 원문", 70),
|
||||
@ -532,7 +573,7 @@ def build_excerpt_sheet(wb: Workbook, excerpts: list[dict], records: dict[str, d
|
||||
sheet.column_dimensions[get_column_letter(index)].width = width
|
||||
sheet.freeze_panes = "D2"
|
||||
legend = (
|
||||
"판정 사유: ①유사도 = 결합유사도 0.65 이상 / ②연속일치 = 똑같은 글자가 80자 이상 이어짐 "
|
||||
"판정 사유: ①유사도 = 결합유사도 0.65 이상 / ②연속일치 = 똑같은 글자가 35자(9어절) 이상 이어짐 "
|
||||
"/ ③커버리지 = 문서의 30% 이상이 겹침. 하나만 충족해도 침해 의심입니다."
|
||||
)
|
||||
order = {"침해 의심": 0, "매칭 미탐지": 1}
|
||||
@ -549,16 +590,18 @@ def build_excerpt_sheet(wb: Workbook, excerpts: list[dict], records: dict[str, d
|
||||
else:
|
||||
reasons = "-"
|
||||
sheet.append([
|
||||
record.get("id") or "-", record.get("매칭 상대 id") or "-",
|
||||
record.get("동일 이메일") or "-",
|
||||
row.get("가명 제목"), row.get("침해 여부"), reasons,
|
||||
row.get("매칭 상대 제목") or "-", row.get("결합유사도"), longest,
|
||||
"\n---\n".join(spans) if spans else "(일치 구간 없음)", row.get("검사 대상 원문"),
|
||||
row.get("매칭 상대 원문") or "(매칭된 상대 글 없음)",
|
||||
])
|
||||
for column in (7, 8, 9):
|
||||
for column in (10, 11, 12):
|
||||
sheet.cell(row=sheet.max_row, column=column).alignment = Alignment(
|
||||
wrap_text=True, vertical="top"
|
||||
)
|
||||
sheet.cell(row=sheet.max_row, column=5).number_format = "0.0000"
|
||||
sheet.cell(row=sheet.max_row, column=8).number_format = "0.0000"
|
||||
sheet.auto_filter.ref = f"A1:{get_column_letter(len(EXCERPT_COLUMNS))}{sheet.max_row}"
|
||||
sheet.append([])
|
||||
sheet.append([legend])
|
||||
@ -639,6 +682,8 @@ def main() -> int:
|
||||
parser.add_argument("--compare-jsonl", type=Path, help="비교 시트를 붙일 이전 회차 JSONL")
|
||||
parser.add_argument("--backend", default="", help="검색 백엔드 표기 (미지정 시 JSONL 값 사용)")
|
||||
parser.add_argument("--note", action="append", default=[], help="요약 시트에 남길 유의사항")
|
||||
parser.add_argument("--hash-map", type=Path,
|
||||
help="가명 해시를 제출 이메일·원문 제목으로 되돌릴 매핑 JSON")
|
||||
parser.add_argument("--sweep-json", type=Path, help="어절 기준 비교 시트용 데이터")
|
||||
parser.add_argument("--exhaustive-json", type=Path,
|
||||
help="문서쌍 전수 대조 결과 (겹침이 0이 되는지 확인한 표)")
|
||||
@ -653,6 +698,8 @@ def main() -> int:
|
||||
records = load(args.jsonl)
|
||||
rows = list(records.values())
|
||||
backend = args.backend or str(rows[0].get("retrieval_backend") or "미기재")
|
||||
if args.hash_map:
|
||||
enrich_with_identity(rows, load_hash_map(args.hash_map))
|
||||
|
||||
wb = Workbook()
|
||||
wb.remove(wb.active)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user