Phase W + V' 완료: before→filled→after 파이프라인 + 조립 로직 수정

Phase W:
- weight 비율 초기 배정 (space_allocator header 높이 반영)
- block_assembler 공통 조립 함수 (filled/assembled 통합)
- filled → Selenium 측정 → context 저장
- sidebar overflow 확장 + body 재배분
- sub_layouts 사전 계산 (이미지 누락 해결)

Phase V':
- 팝업 링크 우측상단 배치 (인라인 → position:absolute)
- 표 내용 Kei 판단 (공란 크기 계산 → 행/열 산출 → Kei 요약)
- 출처 라벨 삭제 + 이미지 아래 캡션 배치
- after 공란 제거 (결론 바로 위까지 body/sidebar 채움)

추가:
- V-10 bold 키워드: 기계적 추출 → Kei 문맥 판단
- ** 마크다운 → <strong> 변환
- [이미지:] 마커 제거 (bold 변환 전 처리)
- grid-template-rows AFTER 크기 반영 (Sonnet final)
- assemble_stage2 CSS font-size override, white-space fix
- 하드코딩 전수 검토 완료
- 본심 여러 topic 텍스트 합침

Phase X 계획 문서 작성 (동적 역할 구조)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 05:00:52 +09:00
parent 24eb1bc5ad
commit 1f7579cf64
64 changed files with 13955 additions and 696 deletions

View File

@@ -531,13 +531,79 @@ def render_slide_from_html(
title = analysis.get("title", "슬라이드")
grid_areas = preset.get("grid_areas", "'header header' 'body sidebar' 'footer footer'")
grid_columns = preset.get("grid_columns", "65fr 35fr")
grid_rows = preset.get("grid_rows", "auto 1fr auto")
# Phase T: 동적 비율 반영 — container_ratio가 있으면 프리셋 고정값 대신 사용
container_ratio = analysis.get("_container_ratio")
if container_ratio and len(container_ratio) == 2:
grid_columns = f"{container_ratio[0]}fr {container_ratio[1]}fr"
else:
grid_columns = preset.get("grid_columns", "65fr 35fr")
# Phase W: AFTER 컨테이너 크기를 grid-template-rows에 반영
# header=auto, body/sidebar=AFTER 높이에 맞춤, footer=AFTER 높이
containers = analysis.get("_containers", {})
redist = analysis.get("_fit_redistribution", {})
from src.fit_verifier import _load_design_tokens as _ldt
_tokens = _ldt()
_header_h = _tokens.get("header_height", 66)
_gap_small = _tokens["spacing_small"]
_bg_h = int(redist.get("배경", containers.get("배경", {}).get("height_px", 0)))
_core_h = int(redist.get("본심", containers.get("본심", {}).get("height_px", 0)))
_footer_h = int(redist.get("결론", containers.get("결론", {}).get("height_px", 0)))
_body_row_h = _bg_h + _core_h + _gap_small if _bg_h and _core_h else 0
if _body_row_h > 0 and _footer_h > 0:
grid_rows = f"auto {_body_row_h}px {_footer_h}px"
else:
grid_rows = preset.get("grid_rows", "auto auto auto").replace("1fr", "auto")
body_html = generated.get("body_html", "")
sidebar_html = generated.get("sidebar_html", "")
footer_html = generated.get("footer_html", "")
# ── 후처리 ──
import re as _re
# 1) sidebar 최외곽 wrapper div만 width:100% (grid cell에 맞추기)
# 첫 번째 태그의 style에서만 변경. 내부 요소(카드 번호 등)는 건드리지 않음.
sidebar_html = _re.sub(
r'^(\s*<div\s+style="[^"]*?)width:\s*\d+px',
r'\1width:100%',
sidebar_html,
count=1,
)
# 2) overflow-y:auto/scroll → overflow:hidden (스크롤 절대 금지)
body_html = _re.sub(r'overflow-y:\s*(auto|scroll)', 'overflow:hidden', body_html)
body_html = _re.sub(r'overflow:\s*(?:auto|scroll)(?!bar)', 'overflow:hidden', body_html)
sidebar_html = _re.sub(r'overflow-y:\s*(auto|scroll)', 'overflow:hidden', sidebar_html)
sidebar_html = _re.sub(r'overflow:\s*(?:auto|scroll)(?!bar)', 'overflow:hidden', sidebar_html)
# 3) markdown **bold** → <strong>
body_html = _re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', body_html)
sidebar_html = _re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', sidebar_html)
# 4) 폰트 위계 강제: 배경 영역 font-size가 본심(core)보다 크면 안 됨
font_h = analysis.get("_font_hierarchy", {})
bg_max = font_h.get("bg", 11.0)
core_max = font_h.get("core", 12.0)
sidebar_max = font_h.get("sidebar", 10.0)
def _cap_font(html_str: str, max_size: float) -> str:
"""font-size: NNpx 중 max_size 초과하는 것을 max_size로 캡."""
def _repl(m):
val = float(m.group(1))
if val > max_size:
return f"font-size:{max_size}px"
return m.group(0)
return _re.sub(r'font-size:\s*(\d+(?:\.\d+)?)px', _repl, html_str)
# body_html의 첫 번째 주요 div(배경)만 캡: height:117px or 배경 색상이 있는 div
# 배경 div 끝(</div> + spacer) 이후가 본심
bg_end = body_html.find('<div style="height:12px;') # spacer between bg and core
if bg_end > 0:
bg_part = body_html[:bg_end]
core_part = body_html[bg_end:]
bg_part = _cap_font(bg_part, bg_max)
body_html = bg_part + core_part
# sidebar 전체 캡
sidebar_html = _cap_font(sidebar_html, sidebar_max)
html = f"""<!DOCTYPE html>
<html lang="ko">
<head>