"""analysis.md layout 문자열을 structure_ontology.yaml로 변환 - family / surface / semantic_role / columns / items / confidence - 기존 figma_audit.py의 _PROPS 매핑과 일관성 유지 """ import sys import json import re from pathlib import Path import yaml sys.path.insert(0, str(Path(__file__).parent)) from phase_common import load_32_frames from figma_audit import _FAMILY, _PROPS, guess_semantic_role, get_family ROOT = Path(r"d:\ad-hoc\kei\design_agent") PREVIEW_DIR = ROOT / "data" / "figma_previews" HERE = Path(__file__).parent # layout → surface 매핑 _SURFACE_OF = { "3col-parallel": "bullets-3", "3col-cards": "cards-3", "3col-compare": "cards-3-compare", "persona-3col": "table-persona-3col", "compare-rows": "table-multi-row", "compare-2col": "bullets-2col", "compare-2banner-top-2col-bottom": "banner-plus-2col", "table-2col": "table-2col", "table-3col": "table-3col", "cycle-3way": "circular-diagram", "circular-nodes": "circular-nodes", "diagram-labels": "labeled-diagram", "diagram-5": "radial-diagram-5", "cards-4": "cards-4-grid", "cards-4plus5": "cards-mixed", "policy-4card-plus-list": "cards-plus-list", "quadrant-issues": "quadrant", "paired-rows": "paired-rows", "central-split": "split-center", "central-5-goals": "radial-center-5", "3-emphasis": "cards-3-horizontal", "3-category": "cards-3-horizontal", "3-section": "cards-3-horizontal", "bullet-cards": "mixed-bullets", "list-numbered": "list-numbered", "list-stacked": "list-stacked", "side-card": "side-card", "full-page-map": "full-page-map", "split-panel-diagram": "split-panel", "split-panel-numbered": "split-panel", "2col-paired": "2col-paired", "2-boxes": "2-boxes", } def confidence_of(family, shape, items, layout): """내가 수동 태깅한 layout에 대한 자체 confidence (휴리스틱)""" if family == "(미분류)" or not shape: return "low" if items and family in {"cards", "list", "compare", "table"}: return "high" if family == "diagram" and not items: return "medium" return "medium" def main(): frames = load_32_frames() 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()} out = {"meta": {"phase": 23, "total_frames": len(frames), "note": "analysis.md의 layout을 속성 체계로 변환. 실험 중 수정 가능."}, "frames": {}} for fid in sorted(frames.keys()): v = frames[fid] layout = v.get("layout", "") family = get_family(layout) props = _PROPS.get(layout, {}) surface = _SURFACE_OF.get(layout, "") role = guess_semantic_role(v.get("content", ""), v.get("keywords", [])) conf = confidence_of(family, props.get("shape", ""), props.get("items"), layout) sid = frame_to_short.get(fid, "?") out["frames"][fid] = { "short_id": sid, "layout_original": layout, # 원본 layout 문자열 (참조용) "family": family, "surface": surface, "semantic_role": role, "columns": props.get("items") if family in {"cards", "compare", "table", "list"} else None, "items": props.get("items"), "has_table": props.get("has_table"), "has_cards": props.get("has_cards"), "has_diagram": props.get("has_diagram"), "confidence": conf, } out_path = HERE / "structure_ontology.yaml" with open(out_path, "w", encoding="utf-8") as f: yaml.safe_dump(out, f, allow_unicode=True, sort_keys=False) print(f"완료: {out_path} ({len(frames)}개 프레임)") # 통계 import collections fam_c = collections.Counter(f["family"] for f in out["frames"].values()) role_c = collections.Counter(f["semantic_role"] for f in out["frames"].values()) conf_c = collections.Counter(f["confidence"] for f in out["frames"].values()) print(f"\nfamily 분포: {dict(fam_c)}") print(f"semantic_role 분포: {dict(role_c.most_common(6))}") print(f"confidence 분포: {dict(conf_c)}") if __name__ == "__main__": main()