Files
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

200 lines
8.2 KiB
Python
Raw Permalink 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.
"""CASE 1 (균등 가중) + CASE 2 (계층 가중) 매트릭스 생성.
각 유닛별 Top-3을 PNG + 점수로 표시."""
import sys
import json
import yaml
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from common import load_figma_texts
from extract_units import extract_units
from methods import (
method_tfidf, method_bm25, method_char_ngram,
method_kiwi_bm25, method_structural,
method_ai_metadata_matcher,
method_hybrid_kiwi_char,
method_tfidf_weighted, method_bm25_weighted,
method_char_ngram_weighted, method_kiwi_bm25_weighted,
method_hybrid_kiwi_char_weighted,
)
ROOT = Path(r"d:\ad-hoc\kei\design_agent")
PREVIEW_DIR = ROOT / "data" / "figma_previews"
UNIT_ORDER = [
("MDX01-intro", "중목차 앞 본문"),
("MDX01-intro-details", "팝업"),
("MDX01-1", "중목차"),
("MDX01-2", "중목차"),
("MDX01-2-image", "이미지"),
("MDX01-2-details", "팝업+표"),
("MDX02-1", "중목차"),
("MDX02-1-image", "이미지"),
("MDX02-2", "중목차(컨테이너)"),
("MDX02-2.1", "소목차"),
("MDX02-2.2", "소목차"),
("MDX02-2.2-table", "표"),
("MDX03-1", "중목차"),
("MDX03-2", "중목차(컨테이너)"),
("MDX03-2.1", "소목차"),
("MDX03-2.1-table", "표"),
("MDX03-2.2", "소목차"),
]
def fmt_score(score, method_name):
if method_name in ("TF-IDF", "Char-ngram", "AI-Meta", "Structural", "하이브리드"):
return f"{score * 100:.0f}%"
else:
return f"{score:.1f}"
def get_preview_cell(fid, short_to_info, png_rel_prefix):
"""프레임 번호 → PNG 썸네일 + 제목 셀"""
short = fid
info = short_to_info.get(short, {})
title = info.get("title_text", "").strip().replace("\n", " ") or ""
if len(title) > 20:
title = title[:20] + "…"
png_rel = f"{png_rel_prefix}{info.get('png', '')}"
return f"![{short}]({png_rel})<br>**{short}**<br>{title}"
def generate_report(case_name, case_desc, methods_def, units, figma, idx_data,
short_to_info, frame_to_short, metadata_db, extra_meta,
out_path, png_rel_prefix):
# 실행
results = {}
for uid, unit_text in units.items():
results[uid] = {}
for mname, fn in methods_def:
if not unit_text.strip():
results[uid][mname] = []
continue
if mname == "AI-Meta":
ranked = method_ai_metadata_matcher(
uid, metadata_db["figma_frames"],
{**metadata_db.get("mdx_sections", {}), **extra_meta}
)
else:
ranked = fn(unit_text, figma)
results[uid][mname] = ranked[:3]
# 리포트 작성
lines = []
lines.append(f"# {case_name}")
lines.append("")
lines.append(case_desc)
lines.append("")
for i, (uid, kind) in enumerate(UNIT_ORDER, 1):
lines.append(f"---")
lines.append("")
lines.append(f"## {i}. {uid} ({kind})")
lines.append("")
# 각 방법별 Top-3 표
lines.append("| 방법 | 1순위 | 2순위 | 3순위 |")
lines.append("|------|-------|-------|-------|")
for mname, _ in methods_def:
cells = [mname]
top3 = results[uid].get(mname, [])
if not top3:
cells.append("(결과 없음)")
cells.append("-")
cells.append("-")
else:
for fid, score in top3:
short = frame_to_short.get(str(fid), "?")
info = short_to_info.get(short, {})
png_file = info.get("png", "")
title = info.get("title_text", "").strip().replace("\n", " ") or ""
if len(title) > 15:
title = title[:15] + "…"
png_rel = f"{png_rel_prefix}{png_file}"
cell = f"![{short}]({png_rel})<br>**{short}** ({fmt_score(score, mname)})<br>{title}"
cells.append(cell)
while len(cells) < 4:
cells.append("-")
lines.append("| " + " | ".join(cells) + " |")
lines.append("")
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"완료: {out_path}")
def main():
figma = load_figma_texts()
units = extract_units()
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()}
short_to_info = idx_data
with open(Path(__file__).parent / "metadata_db.yaml", encoding="utf-8") as f:
metadata_db = yaml.safe_load(f)
# extra concepts for 17 units
extra_meta = {
"MDX01-intro-details": {"concepts": ["정책", "디지털화", "BIM", "스마트건설", "사례"], "layout_hint": "popup-list"},
"MDX01-2-image": {"concepts": ["DX", "핵심기술", "상호관계", "GIS", "BIM", "디지털트윈"], "layout_hint": "diagram"},
"MDX01-2-details": {"concepts": ["BIM", "DX", "비교", "범위", "S/W", "프로세스", "성과품", "활용", "확장성", "수행개념", "CIVIL", "IT", "주체", "발주처", "설계사", "시공사"], "layout_hint": "compare-rows"},
"MDX02-1-image": {"concepts": ["DX", "목표", "안전", "품질", "생산성", "소통", "신뢰"], "layout_hint": "cycle-3way"},
"MDX02-2.1": {"concepts": ["Process", "변화", "수작업", "S/W", "체계화", "2D", "3D", "협업", "검증", "사전"], "layout_hint": "transition-list"},
"MDX02-2.2": {"concepts": ["발주자", "시공자", "설계자", "역량", "기대효과", "3D모델", "협업", "Claim", "리스크", "품질"], "layout_hint": "persona-3col"},
"MDX02-2.2-table": {"concepts": ["발주자", "시공자", "설계자", "필요역량", "업무", "변화", "3D", "검증", "협업", "표"], "layout_hint": "table-3col"},
"MDX03-2.1": {"concepts": ["Process", "Analogue", "Digital", "혁신", "GIS", "BIM", "Solution", "2D", "3D", "협업"], "layout_hint": "compare-2col"},
"MDX03-2.1-table": {"concepts": ["Analogue", "Digital", "As-is", "To-be", "2D", "3D", "문서", "행정", "시각화", "소통", "표"], "layout_hint": "compare-2col"},
"MDX03-2.2": {"concepts": ["Product", "결과", "성과물", "품질", "Digital", "정보물", "Solution", "협업", "통합관리"], "layout_hint": "compare-2col"},
}
png_rel = "../../data/figma_previews/"
# ═══ CASE 1: 균등 가중 ═══
case1_methods = [
("TF-IDF", method_tfidf),
("BM25", method_bm25),
("Char-ngram", method_char_ngram),
("Kiwi+BM25", method_kiwi_bm25),
("Structural", method_structural),
("AI-Meta", None),
("하이브리드", method_hybrid_kiwi_char),
]
generate_report(
case_name="CASE 1 — 균등 가중 매칭",
case_desc="전체 텍스트(블릿 포함)를 동일 가중치로 토큰화. 하이브리드 = Kiwi+BM25 × 0.5 + Char n-gram × 0.5",
methods_def=case1_methods,
units=units, figma=figma, idx_data=idx_data,
short_to_info=short_to_info, frame_to_short=frame_to_short,
metadata_db=metadata_db, extra_meta=extra_meta,
out_path=Path(__file__).parent / "MATRIX_CASE1.md",
png_rel_prefix=png_rel,
)
# ═══ CASE 2: 계층 가중 ═══
case2_methods = [
("TF-IDF", method_tfidf_weighted),
("BM25", method_bm25_weighted),
("Char-ngram", method_char_ngram_weighted),
("Kiwi+BM25", method_kiwi_bm25_weighted),
("Structural", method_structural),
("AI-Meta", None),
("하이브리드", method_hybrid_kiwi_char_weighted),
]
generate_report(
case_name="CASE 2 — 계층 가중 매칭",
case_desc="중목차(##) ×3, 소목차(###) ×3, 굵은 글씨 라벨(**xx**) ×2 가중 토큰화. 하이브리드 = 가중 Kiwi+BM25 × 0.5 + 가중 Char n-gram × 0.5",
methods_def=case2_methods,
units=units, figma=figma, idx_data=idx_data,
short_to_info=short_to_info, frame_to_short=frame_to_short,
metadata_db=metadata_db, extra_meta=extra_meta,
out_path=Path(__file__).parent / "MATRIX_CASE2.md",
png_rel_prefix=png_rel,
)
if __name__ == "__main__":
main()