Files
C.E.L_Slide_test2/tests/matching/matrix_simple.py
T
KyeongminandClaude Opus 4.8 b836e79ee1 wip: phase_z2 evidence 파이프라인 + matching 실험(phase2~26) + 프론트 trace 패널 진행분 스냅샷
- src: phase_z2 composition/mapper/pipeline/placement_planner/retry, ai_fallback(prompts/schema/validate), mdx_text_atoms 신규
- Front: PipelineTracePanel 신규, FramePanel/SlideCanvas/Home/designAgentApi 등 갱신 + 테스트 4종 추가
- templates/phase_z2: catalog(component_expansion_registry, node_slot_mapping 신규), frames, families, slide_base 갱신
- tests/matching: phase2~26 매칭 실험 스크립트·리포트·온톨로지 전체 (미커밋 진행분)
- tests: b4_v4 evidence, task5~28.5 시리즈, regression(imp95 baseline) 등 신규 테스트 대량 추가
- docs/reference: MDX 구조 인벤토리, MDX→Frame 구조 계약 문서
- scripts: mdx 계약/parity/coverage/viewport 체크, gitea comment, run sync 유틸
- .gitignore: tmp*.json, chromedriver, .orchestrator, *.pkl, Front_test* 등 임시/스냅샷 제외

미완성 작업의 보존용 스냅샷 커밋 (2026-07-02)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 17:03:42 +09:00

151 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""단순 매칭 매트릭스: MDX 섹션 × 8 방법 = 매칭된 프레임 번호 + 점수"""
import sys
import json
import yaml
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from common import load_ground_truth, load_figma_texts, load_mdx_sections
from methods import (
method_tfidf, method_bm25, method_char_ngram,
method_kiwi_bm25, method_structural,
method_ai_metadata_matcher, method_weighted, method_hard_filter,
)
ROOT = Path(r"d:\ad-hoc\kei\design_agent")
PREVIEW_DIR = ROOT / "data" / "figma_previews"
def normalize_score(score, method_name):
"""방법별 점수 스케일이 달라서 0~100% 범위로 정규화.
- TF-IDF, Char-ngram, AI-Meta, Weighted: 이미 0~1 → ×100
- Structural: 0~1 → ×100
- BM25, Kiwi+BM25, HardFilter: raw 점수 (0~200+) → top1을 100%로 상대화
"""
return score # 원래 점수 그대로 반환 (아래에서 별도 처리)
def fmt_score(score, method_name, max_score=None):
"""점수를 읽기 좋게 포매팅."""
if method_name in ("TF-IDF", "Char-ngram", "AI-Meta", "Weighted", "Structural"):
# 0~1 스케일 → %
return f"{score * 100:.0f}%"
else:
# BM25 계열: raw 점수. max 대비 상대값
if max_score and max_score > 0:
rel = score / max_score * 100
return f"{rel:.0f}% ({score:.1f})"
return f"{score:.1f}"
def main():
gt_list = load_ground_truth()
figma = load_figma_texts()
mdx = load_mdx_sections()
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()}
with open(Path(__file__).parent / "metadata_db.yaml", encoding="utf-8") as f:
metadata_db = yaml.safe_load(f)
methods_def = [
("TF-IDF", method_tfidf),
("BM25", method_bm25),
("Char-ngram", method_char_ngram),
("Kiwi+BM25", method_kiwi_bm25),
("Structural", method_structural),
("AI-Meta", None),
("Weighted", method_weighted),
("HardFilter", method_hard_filter),
]
# 각 섹션/방법별 Top-3 (score 포함)
top3_data = {}
for sec_id, sec_text in mdx.items():
top3_data[sec_id] = {}
for name, fn in methods_def:
if name == "AI-Meta":
ranked = method_ai_metadata_matcher(
sec_id, metadata_db["figma_frames"], metadata_db["mdx_sections"]
)
else:
ranked = fn(sec_text, figma)
top3_data[sec_id][name] = ranked[:3]
# ──────────────────────
# 리포트 생성
# ──────────────────────
lines = []
lines.append("# MDX ↔ Figma 매칭 매트릭스 (점수 포함)")
lines.append("")
lines.append("각 셀 형식: `프레임번호(점수)`")
lines.append("")
lines.append("- TF-IDF / Char-ngram / AI-Meta / Weighted / Structural: 0~100% (코사인 or Jaccard)")
lines.append("- BM25 / Kiwi+BM25 / HardFilter: raw 점수 (상대 비교용, 절대값은 문서길이/어휘량에 따라 달라짐)")
lines.append("")
# ══ Top-1 매트릭스 (점수 포함) ══
lines.append("## Top-1 (1순위)")
lines.append("")
method_names = [m[0] for m in methods_def]
header = "| MDX 섹션 | " + " | ".join(method_names) + " |"
lines.append(header)
lines.append("|" + "---|" * (len(method_names) + 1))
for gt in gt_list:
sid = gt["id"]
cells = [sid]
for mname in method_names:
top = top3_data[sid][mname][:1]
if not top:
cells.append("-")
continue
fid, score = top[0]
short = frame_to_short.get(str(fid), "?")
cells.append(f"**{short}** ({fmt_score(score, mname)})")
lines.append("| " + " | ".join(cells) + " |")
lines.append("")
# ══ Top-3 매트릭스 (점수 포함) ══
lines.append("## Top-3 (1/2/3순위)")
lines.append("")
for gt in gt_list:
sid = gt["id"]
lines.append(f"### {sid}")
lines.append("")
lines.append("| 방법 | 1순위 | 2순위 | 3순위 |")
lines.append("|------|-------|-------|-------|")
for mname in method_names:
cells = [mname]
for fid, score in top3_data[sid][mname][:3]:
short = frame_to_short.get(str(fid), "?")
cells.append(f"**{short}** ({fmt_score(score, mname)})")
while len(cells) < 4:
cells.append("-")
lines.append("| " + " | ".join(cells) + " |")
lines.append("")
# ══ 프레임 번호 참고 ══
lines.append("## 프레임 번호 참고")
lines.append("")
lines.append("| # | 제목 | 미리보기 |")
lines.append("|---|------|---------|")
for sid in sorted(idx_data.keys()):
info = idx_data[sid]
title = info.get("title_text", "").strip().replace("\n", " ") or "_(제목 없음)_"
if len(title) > 50:
title = title[:50] + "…"
png_rel = f"../../data/figma_previews/{info['png']}"
lines.append(f"| **{sid}** | {title} | ![{sid}]({png_rel}) |")
lines.append("")
out_path = Path(__file__).parent / "MATRIX.md"
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"완료: {out_path}")
if __name__ == "__main__":
main()