"""32 Figma frames 의 '후보 키워드' 전수 확인 + 통계. 출력: - FIGMA_KEYWORDS_REPORT.md : 프레임별 후보 키워드 + 통계 + DF 기반 tier 용도: analysis.md 의 '후보 키워드' 필드가 어떻게 채워져 있는지 한눈 검수. """ import sys import collections from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from phase_common import load_32_frames, compute_df_idf_tier, load_frame_index HERE = Path(__file__).parent def main(): frames = load_32_frames() df, idf, tier, N = compute_df_idf_tier(frames) idx_data, frame_to_short = load_frame_index() # 프레임 순 정렬 (short_id) ordered = sorted(frames.items(), key=lambda kv: frame_to_short.get(kv[0], "99")) lines = [] lines.append("# Figma 32 프레임 — 후보 키워드 검수 리포트") lines.append("") lines.append("**출처**: 각 프레임의 `figma_to_html_agent/blocks/{frame_id}/analysis.md` 의 `## 후보 키워드` 필드") lines.append("") lines.append(f"**작성자**: claude-opus-4-7 (2026-04-21, `tagged_by` 메타 참조)") lines.append("") lines.append(f"**생성 방법**: 각 프레임의 `texts.md` (MCP 추출 원본 텍스트 전수) + `flat.md` " f"(bottom-up 평탄화 + 이상 탐지) 를 AI 가 읽고 15~25개 어휘를 수동 태깅.") lines.append("") # 1. 전체 통계 lines.append("## 1. 전체 통계") lines.append("") total_kws = sum(len(v["keywords"]) for _, v in frames.items()) unique_kws = len(set().union(*[set(v["keywords"]) for v in frames.values()])) avg_kws = total_kws / len(frames) core = [kw for kw in set().union(*[set(v["keywords"]) for v in frames.values()]) if tier.get(kw) == "core"] mid = [kw for kw in set().union(*[set(v["keywords"]) for v in frames.values()]) if tier.get(kw) == "mid"] general = [kw for kw in set().union(*[set(v["keywords"]) for v in frames.values()]) if tier.get(kw) == "general"] lines.append(f"- 프레임 수: **{len(frames)}**") lines.append(f"- 총 키워드 (중복 포함): **{total_kws}**") lines.append(f"- 고유 키워드: **{unique_kws}**") lines.append(f"- 프레임당 평균: **{avg_kws:.1f}개**") lines.append("") lines.append(f"- **core** (df ≤ 10%, 1~3 프레임 등장): **{len(core)}개** — 핵심 가중치 ×1.0") lines.append(f"- **mid** (df 10~30%): **{len(mid)}개** — 가중치 ×0.5") lines.append(f"- **general** (df ≥ 30%): **{len(general)}개** — 가중치 ×0.1") lines.append("") # 2. 프레임별 리스트 lines.append("## 2. 프레임별 후보 키워드") lines.append("") lines.append("| # | Frame | 제목 (content 1문장) | 키워드 수 | 키워드 |") lines.append("|---|-------|---------------------|----------|--------|") for fid, v in ordered: sid = frame_to_short.get(fid, "?") content = v.get("content", "").replace("\n", " ")[:60] kws = v["keywords"] kws_str = ", ".join(kws) lines.append(f"| {sid} | {fid} | {content}… | {len(kws)} | {kws_str} |") lines.append("") # 3. tier 별 전체 키워드 lines.append("## 3. Tier 별 전체 키워드 (매칭 가중치 분류)") lines.append("") def sort_by_df(kws): return sorted(kws, key=lambda k: (-df.get(k, 0), k)) lines.append(f"### 3-1. Core ({len(core)}개, df ≤ 10% — 가중치 ×1.0)") lines.append("") lines.append("특정 프레임에만 등장하는 고유 어휘. 매칭에서 결정적 신호.") lines.append("") core_sorted = sort_by_df(core) lines.append(", ".join(f"`{k}`({df.get(k,0)})" for k in core_sorted[:80])) if len(core_sorted) > 80: lines.append(f"... (총 {len(core_sorted)}개)") lines.append("") lines.append(f"### 3-2. Mid ({len(mid)}개, df 10~30% — 가중치 ×0.5)") lines.append("") mid_sorted = sort_by_df(mid) lines.append(", ".join(f"`{k}`({df.get(k,0)})" for k in mid_sorted)) lines.append("") lines.append(f"### 3-3. General ({len(general)}개, df ≥ 30% — 가중치 ×0.1)") lines.append("") lines.append("여러 프레임에 등장해 변별력이 낮은 범용어.") lines.append("") general_sorted = sort_by_df(general) lines.append(", ".join(f"`{k}`({df.get(k,0)})" for k in general_sorted)) lines.append("") # 4. 어떻게 쓰는가 lines.append("## 4. 매칭에서의 활용 (Phase 23)") lines.append("") lines.append("```") lines.append("MDX 본문 →") lines.append(" synonyms.yaml 치환 →") lines.append(" Kiwi 형태소 분석 (명사/영문/숫자만) →") lines.append(" 위 vocab (32개 프레임 전체 키워드 합집합) 과 교집합 →") lines.append(" MDX 키워드 셋 확보") lines.append("") lines.append("각 프레임 점수 = IDF 가중 Jaccard(MDX 키워드 셋, 프레임 키워드 셋)") lines.append(" 여기서 각 키워드 기여도는 df 기반 tier 가중치 적용") lines.append("```") lines.append("") lines.append("**사용처**:") lines.append("- Phase 23 (키워드만), 24 (+내용), 25 (+구조) — **legacy 축**") lines.append("- Phase 26 (template-fit-v1) 는 이 키워드 리스트 대신 " "프레임별 `anchor_sets` (구조화된 named set) 사용") lines.append("") # 5. 원본 확인법 lines.append("## 5. 원본 파일 직접 확인") lines.append("") lines.append("각 프레임의 analysis.md 에 그대로 기록:") lines.append("") lines.append("```bash") lines.append("cat figma_to_html_agent/blocks/1171281190/analysis.md") lines.append("```") lines.append("") lines.append("전체 검수:") lines.append("") lines.append("```bash") lines.append("grep -A 2 '## 후보 키워드' figma_to_html_agent/blocks/*/analysis.md") lines.append("```") lines.append("") out = HERE / "FIGMA_KEYWORDS_REPORT.md" out.write_text("\n".join(lines), encoding="utf-8") print(f"완료: {out}") if __name__ == "__main__": main()