"""Phase 10 — 타이틀 ONLY 매칭 실험 질문: 본문 제외, 대제목/중제목/소제목만으로 매칭하면 MDX03-1이 풀릴까? 구성: - MDX 유닛: frontmatter title(대제목) + 중제목 + 소제목만 합쳐서 쿼리로 사용 (본문 제외) - Figma 프레임: ## 타이틀 섹션 내용만 사용 (본문 제외) """ import sys import json import re import os from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from methods import ( method_tfidf, method_char_ngram, method_kiwi_bm25, method_distinctive_kiwi, method_sbert_chunk, method_e5_chunk, method_cross_encoder, method_hybrid_bm25_cross, ) ROOT = Path(r"d:\ad-hoc\kei\design_agent") MDX_DIR = ROOT / "samples" / "mdx_batch" BLOCKS_DIR = ROOT / "figma_to_html_agent" / "blocks" PREVIEW_DIR = ROOT / "data" / "figma_previews" def extract_titles_only_mdx(fname, mid_title, sub_title=None): """MDX 파일의 frontmatter title + 지정된 중/소제목 반환 (본문 제외)""" with open(MDX_DIR / fname, encoding="utf-8") as f: content = f.read() # frontmatter title 추출 m = re.search(r"^---\s*\n(.*?)\n---", content, re.DOTALL | re.MULTILINE) big_title = "" if m: tm = re.search(r"title:\s*(.+)", m.group(1)) if tm: big_title = tm.group(1).strip() parts = [big_title, mid_title] if sub_title: parts.append(sub_title) return " / ".join([p for p in parts if p]) def extract_titles_only_figma(): """각 Figma 프레임의 첫 번째 ## 섹션 전체를 타이틀로 추출 - ## 타이틀 있으면 그 섹션, 없으면 첫 ## 섹션 (예: Frame 14의 '## 뱃지 라벨') - 섹션 안의 ### 하위 헤더는 **내용은 유지하고 라벨 줄만 제거** - 다음 ##(같은 레벨) 를 만나면 종료 """ out = {} for d in sorted(os.listdir(BLOCKS_DIR)): p = BLOCKS_DIR / d / "texts.md" if not p.is_file(): continue with open(p, encoding="utf-8") as f: text = f.read() lines = text.split("\n") # 첫 번째 ## 헤더 위치 찾기 first_h2 = None for i, ln in enumerate(lines): if re.match(r"^##\s+\S", ln): first_h2 = i break if first_h2 is None: out[d] = "" continue # 다음 ##(level 2) 나올 때까지 내용 수집 parts = [] for i in range(first_h2 + 1, len(lines)): ln = lines[i] if re.match(r"^##\s+\S", ln): break # 다음 ## 섹션 시작 → 종료 # ### 이상 서브 헤더는 라벨 제거, 내용은 유지 if re.match(r"^#{3,}\s", ln): continue s = ln.strip() if not s or s.startswith("---"): continue clean = re.sub(r"^-\s*", "", s) if clean: parts.append(clean) out[d] = " ".join(parts) return out TARGET_UNITS = [ # (unit_id, display, correct_short_id, mdx_file, mid_title, sub_title) ("MDX01-2-details", "1. (MDX 1) 팝업 — DX와 BIM의 구분", "18", "01.mdx", "2. 용어간 상호관계", None), ("MDX02-2.2-table", "2. (MDX 2) 2.2 DX 시행 주체별 기대효과", "14", "02.mdx", "2. DX 기반 Process 혁신에 따른 주체별 기대효과", "2.2 DX 시행 주체별 기대효과"), ("MDX03-1", "3. (MDX 03) 1. DX 시행을 위한 필수요건", "13", "03.mdx", "1. DX 시행을 위한 필수 요건", None), ("MDX03-2", "4. (MDX 03) 2. Process 혁신과 Product 변화", "29", "03.mdx", "2. Process의 혁신과 Product의 변화", None), ] def main(): # 타이틀-only 데이터 구성 mdx_titles = {} for uid, _, _, fname, mid, sub in TARGET_UNITS: mdx_titles[uid] = extract_titles_only_mdx(fname, mid, sub) figma_titles = extract_titles_only_figma() with open(PREVIEW_DIR / "index.json", encoding="utf-8") as f: idx_data = json.load(f) frame_to_short = {info["frame_id"]: sid for sid, info in idx_data.items()} print("=" * 70) print("타이틀 ONLY 구성 확인") print("=" * 70) for uid, display, correct_id, _, _, _ in TARGET_UNITS: print(f"\n[{uid}] 정답 = {correct_id}") print(f" MDX 쿼리: {mdx_titles[uid]}") info = idx_data.get(correct_id, {}) fid = info.get("frame_id", "") correct_title = figma_titles.get(fid, "") print(f" Figma {correct_id} 타이틀: {correct_title}") methods = [ ("TF-IDF", method_tfidf), ("Char 3-gram", method_char_ngram), ("Kiwi+BM25", method_kiwi_bm25), ("Distinctive-Kiwi", method_distinctive_kiwi), ("청킹+SBERT", method_sbert_chunk), ("청킹+E5", method_e5_chunk), ("Cross", method_cross_encoder), ("BM25 → Cross rerank", lambda m, f: method_hybrid_bm25_cross(m, f, top_k=5)), ] print("\n" + "=" * 70) print("타이틀 ONLY — 8개 방법 1순위 정답률") print("=" * 70) strategy_results = {} for sname, fn in methods: top3_by = {} results = [] for uid, _, correct_id, _, _, _ in TARGET_UNITS: query = mdx_titles[uid] try: ranked = fn(query, figma_titles) top3 = [frame_to_short.get(str(fid), "?") for fid, _ in ranked[:3]] except Exception as e: top3 = ["ERR", "-", "-"] print(f"ERR {sname} {uid}: {e}") top3_by[uid] = top3 results.append(top3[0] == correct_id) marks = ["✓" if r else "✗" for r in results] score = sum(results) strategy_results[sname] = (results, top3_by) print(f" {sname:28s} {' '.join(marks)} = {score}/4") # MD 리포트 png_rel = "../../data/figma_previews/" lines = [] lines.append("# Phase 10 — 타이틀 ONLY 매칭 실험") lines.append("") lines.append("**질문**: 본문 제외, 대제목+중제목(+소제목)만 vs Figma ## 타이틀 섹션만 매칭 시?") lines.append("") lines.append("### 구성 확인") lines.append("") lines.append("| 유닛 | MDX 쿼리 (타이틀 only) | 정답 Frame 타이틀 |") lines.append("|------|------------------------|-------------------|") for uid, display, correct_id, _, _, _ in TARGET_UNITS: info = idx_data.get(correct_id, {}) fid = info.get("frame_id", "") correct_title = figma_titles.get(fid, "") lines.append(f"| {display} | `{mdx_titles[uid]}` | `{correct_title}` (Frame {correct_id}) |") lines.append("") lines.append("### 타이틀 ONLY — 1순위 정답률") lines.append("") lines.append("| 방법 | MDX1 팝업(18) | MDX2 2.2(14) | MDX03-1(13) | MDX03-2(29) | 합계 |") lines.append("|------|---------------|--------------|-------------|-------------|------|") for sname, _ in methods: results, top3_by = strategy_results[sname] marks = [] for idx, (uid, _, correct_id, _, _, _) in enumerate(TARGET_UNITS): t3 = top3_by[uid] mark = "✓" if results[idx] else f"✗({t3[0]})" marks.append(mark) score = sum(results) lines.append(f"| {sname} | {marks[0]} | {marks[1]} | {marks[2]} | {marks[3]} | **{score}/4** |") lines.append("") lines.append("---") lines.append("") lines.append("## 유닛별 전략 Top-3 상세") lines.append("") for uid, display, correct_id, _, _, _ in TARGET_UNITS: lines.append(f"### {display} — 정답 Frame **{correct_id}**") lines.append("") lines.append("| 방법 | 1순위 | 2순위 | 3순위 |") lines.append("|------|-------|-------|-------|") for sname, _ in methods: _, top3_by = strategy_results[sname] t3 = top3_by[uid] row = [sname] for sid in t3: info = idx_data.get(sid, {}) png = info.get("png", "") title = info.get("title_text", "").strip().replace("\n", " ") or "" if len(title) > 15: title = title[:15] + "…" mark = "⭐ " if sid == correct_id else "" cell = f"{mark}![{sid}]({png_rel}{png})
**{sid}**
{title}" row.append(cell) lines.append("| " + " | ".join(row) + " |") lines.append("") out_path = Path(__file__).parent / "MATRIX_PHASE10.md" out_path.write_text("\n".join(lines), encoding="utf-8") print(f"\n완료: {out_path}") if __name__ == "__main__": main()