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>
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
"""BEPS 전문(1171281171/texts.md)에서 synonym 후보 mining.
|
||||
|
||||
Mining 전략:
|
||||
1. 알려진 canonical 기준 — BEPS에서 등장하는 변형 확인
|
||||
2. 한영 병기 패턴 — `XXX (YYY)`, `XXX: YYY`
|
||||
3. 띄어쓰기 변형 — 같은 명사구의 공백 변형들
|
||||
4. 형태 유사 — Kiwi 토큰화 후 편집거리 근접
|
||||
"""
|
||||
import sys
|
||||
import re
|
||||
import collections
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from methods import _get_kiwi, _extract_content_tokens
|
||||
|
||||
ROOT = Path(r"d:\ad-hoc\kei\design_agent")
|
||||
BEPS_FILE = ROOT / "figma_to_html_agent" / "blocks" / "1171281171" / "texts.md"
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
|
||||
def load_beps():
|
||||
"""BEPS 텍스트의 실제 내용 라인만 (메타 제거)"""
|
||||
text = BEPS_FILE.read_text(encoding="utf-8")
|
||||
lines = []
|
||||
for ln in text.split("\n"):
|
||||
s = ln.strip()
|
||||
if not s: continue
|
||||
if s.startswith("#"): continue
|
||||
if s.startswith(">"): continue
|
||||
if s.startswith("- "):
|
||||
lines.append(s[2:].strip())
|
||||
else:
|
||||
lines.append(s)
|
||||
return lines
|
||||
|
||||
|
||||
# ═══ 전략 1: 기존 canonical 기준 변형 확인 ═══
|
||||
def strategy_known_canonicals(lines, canonicals):
|
||||
"""알려진 canonical 각각에 대해 BEPS에서 어떤 표기로 등장하는지"""
|
||||
result = {}
|
||||
for c in canonicals:
|
||||
# 공백 없는 형태 + 공백 있는 형태 모두
|
||||
no_space = c.replace(" ", "")
|
||||
variants_found = set()
|
||||
for ln in lines:
|
||||
# exact match of canonical
|
||||
if c in ln:
|
||||
variants_found.add(c)
|
||||
# no-space variant
|
||||
if no_space != c and no_space in ln:
|
||||
variants_found.add(no_space)
|
||||
# space-separated variant (글자 사이 공백 삽입)
|
||||
if len(c) >= 2 and " " not in c:
|
||||
# e.g. "필수조건" → "필수 조건" 검색
|
||||
for split_pos in range(1, len(c)):
|
||||
with_space = c[:split_pos] + " " + c[split_pos:]
|
||||
if with_space in ln:
|
||||
variants_found.add(with_space)
|
||||
result[c] = variants_found
|
||||
return result
|
||||
|
||||
|
||||
# ═══ 전략 2: 한영 병기 패턴 ═══
|
||||
def strategy_paren_pairs(lines):
|
||||
"""`한글 (English)` 또는 `English (한글)` 패턴"""
|
||||
pairs = []
|
||||
# 패턴 1: "한글단어 (영어단어)"
|
||||
p1 = re.compile(r"([가-힣][가-힣\s]*[가-힣])\s*\(([A-Za-z][A-Za-z\s&\.]*[A-Za-z])\)")
|
||||
# 패턴 2: "영어단어 (한글단어)"
|
||||
p2 = re.compile(r"([A-Za-z][A-Za-z\s&\.]*[A-Za-z])\s*\(([가-힣][가-힣\s]*[가-힣])\)")
|
||||
for ln in lines:
|
||||
for m in p1.finditer(ln):
|
||||
k, e = m.group(1).strip(), m.group(2).strip()
|
||||
if 2 <= len(k) <= 20 and 2 <= len(e) <= 40:
|
||||
pairs.append((k, e))
|
||||
for m in p2.finditer(ln):
|
||||
e, k = m.group(1).strip(), m.group(2).strip()
|
||||
if 2 <= len(k) <= 20 and 2 <= len(e) <= 40:
|
||||
pairs.append((k, e))
|
||||
return pairs
|
||||
|
||||
|
||||
# ═══ 전략 3: 띄어쓰기 변형 (Kiwi 기반) ═══
|
||||
def strategy_spacing(lines):
|
||||
"""같은 연속 명사구가 '공백 버전'과 '붙인 버전' 둘 다 등장하는 경우"""
|
||||
# 명사구 후보 추출
|
||||
kiwi = _get_kiwi()
|
||||
all_text = " ".join(lines)
|
||||
# 2~4자 명사구 반복 찾기
|
||||
freq = collections.Counter()
|
||||
for ln in lines:
|
||||
tokens = _extract_content_tokens(ln, kiwi)
|
||||
# 2-gram 명사구
|
||||
for i in range(len(tokens) - 1):
|
||||
a, b = tokens[i], tokens[i + 1]
|
||||
if 1 <= len(a) <= 4 and 1 <= len(b) <= 4:
|
||||
spaced = f"{a} {b}"
|
||||
joined = f"{a}{b}"
|
||||
if spaced in all_text and joined in all_text:
|
||||
freq[(joined, spaced)] += 1
|
||||
return [(j, s) for (j, s), c in freq.most_common(50)]
|
||||
|
||||
|
||||
# ═══ 전략 4: 괄호 안의 약어 ═══
|
||||
# e.g., "Geographic Information System (GIS)"
|
||||
def strategy_abbrev_expansion(lines):
|
||||
p = re.compile(r"([A-Za-z][A-Za-z\s]{3,60})\s*\(([A-Z]{2,6})\)")
|
||||
out = []
|
||||
for ln in lines:
|
||||
for m in p.finditer(ln):
|
||||
full, abbr = m.group(1).strip(), m.group(2).strip()
|
||||
if 2 < len(full) < 50 and 2 <= len(abbr) <= 6:
|
||||
out.append((abbr, full))
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
lines = load_beps()
|
||||
print(f"BEPS 본문 라인 수: {len(lines)}")
|
||||
print()
|
||||
|
||||
# 전략 1: 기존 canonical
|
||||
canonicals = ["필수조건", "DX", "BIM", "과정혁신", "결과혁신",
|
||||
"3D모델", "2D도면", "발주자", "시공자", "설계자",
|
||||
"디지털기술", "전문지식", "Process", "Product",
|
||||
"성장동력", "고부가가치", "건설산업"]
|
||||
print("=== 전략 1: 알려진 canonical의 BEPS 등장 변형 ===")
|
||||
r1 = strategy_known_canonicals(lines, canonicals)
|
||||
for c, variants in r1.items():
|
||||
if variants:
|
||||
print(f" {c:12s} → {sorted(variants)}")
|
||||
print()
|
||||
|
||||
# 전략 2: 한영 병기
|
||||
print("=== 전략 2: 한영 병기 패턴 (상위 20개) ===")
|
||||
r2 = strategy_paren_pairs(lines)
|
||||
counter2 = collections.Counter(r2)
|
||||
for (k, e), cnt in counter2.most_common(20):
|
||||
print(f" '{k}' ↔ '{e}' ({cnt}회)")
|
||||
print()
|
||||
|
||||
# 전략 3: 띄어쓰기 변형
|
||||
print("=== 전략 3: 띄어쓰기 변형 (같은 연속 명사구가 공백/붙임 둘다) ===")
|
||||
r3 = strategy_spacing(lines)
|
||||
for joined, spaced in r3[:20]:
|
||||
print(f" '{joined}' ↔ '{spaced}'")
|
||||
print()
|
||||
|
||||
# 전략 4: 약어 풀네임
|
||||
print("=== 전략 4: 영어 약어 풀네임 ===")
|
||||
r4 = strategy_abbrev_expansion(lines)
|
||||
counter4 = collections.Counter(r4)
|
||||
for (abbr, full), cnt in counter4.most_common(20):
|
||||
print(f" '{abbr}' ≡ '{full}' ({cnt}회)")
|
||||
print()
|
||||
|
||||
# 결과를 YAML 후보로 저장
|
||||
proposals = {
|
||||
"from_known_canonicals": {c: sorted(v) for c, v in r1.items() if v},
|
||||
"ko_en_paren_pairs": [{"ko": k, "en": e, "count": cnt}
|
||||
for (k, e), cnt in counter2.most_common(30)],
|
||||
"spacing_variants": [{"joined": j, "spaced": s} for j, s in r3[:30]],
|
||||
"abbreviation_expansions": [{"abbr": a, "full": f, "count": cnt}
|
||||
for (a, f), cnt in counter4.most_common(30)],
|
||||
}
|
||||
out_path = HERE / "SYNONYM_MINING_PROPOSALS.yaml"
|
||||
with open(out_path, "w", encoding="utf-8") as f:
|
||||
yaml.safe_dump(proposals, f, allow_unicode=True, sort_keys=False)
|
||||
print(f"완료: {out_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user