reports 수정 및 script 수정 .

This commit is contained in:
hbyang 2026-09-07 10:45:33 +09:00
parent 6b27fff509
commit 1e56bdf1c0
3 changed files with 50 additions and 3 deletions

Binary file not shown.

View File

@ -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)