- 루트의 IMPROVEMENT-PHASE-*.md, PHASE-*.md 등 45개 → docs/history/로 이동 - docs/block-tests/ 오래된 블록 테스트 HTML 삭제 (figma_to_html_agent로 대체) - docs/figma-analysis/, docs/figma-assets/, docs/figma-screenshots/ 정리 - docs/test-*.html 등 초기 테스트 파일 정리 - 참고 페이지/ 스크린샷 정리 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
18 KiB
18 KiB
Phase R': 접근 C 기반 — 블록 CSS 참고 + AI 구조 결정
작성일: 2026-03-30 상태: 설계 선행: Phase P(20점), Q(블록 선택 개선), R(실패 — 기존 구조 위에 패치) 근거: C_reference.png + hybrid_simulation.png 시뮬레이션 검증
1. Phase P, Q, R에서 무엇이 문제였는가
P, Q, R 전부 같은 구조:
블록을 선택한다 → 그 블록의 슬롯에 텍스트를 채운다
이 구조의 근본 한계:
- 블록이 구조를 결정한다. 콘텐츠가 아니라 블록 템플릿이 HTML 구조를 고정.
- topic 1개 = 블록 1개. 합침/분리 불가.
- 38개 고정 템플릿에 없는 구조(포함 관계, Before→After 등)는 표현 불가.
- 콘텐츠 전달 의도(expression_hint)가 HTML 구조에 반영되지 않음.
Phase Q에서 블록 선택 정확도를 올렸고, Phase R에서 variant를 추가했지만, 근본 구조("블록 선택 → 슬롯 채우기")는 P = Q = R 동일. 결과물도 동일 수준.
2. 접근 C: 무엇이 달라지는가
핵심 전환
현재 (P=Q=R):
블록이 구조를 결정 → 콘텐츠를 슬롯에 채움
(블록 중심)
접근 C:
콘텐츠가 구조를 결정 → 블록 CSS를 참고하여 HTML 생성
(콘텐츠 중심)
"블록을 참고하여 만든다"의 정확한 의미
블록을 버리는 것이 아니다. 블록을 "선택"하는 것도 아니다.
| 현재 (블록 선택) | 접근 C (블록 참고) | |
|---|---|---|
| 블록의 역할 | HTML 구조를 결정하는 템플릿 | CSS 스타일(색상, 폰트, 배경, radius)의 참고 자료 |
| 누가 구조를 결정 | 블록 템플릿 (Jinja2) | AI가 콘텐츠 전달 의도를 보고 결정 |
| topic 합침/분리 | 불가 (1 topic = 1 블록) | 가능 (AI가 판단) |
| 포함 관계 시각화 | 해당 블록이 없으면 불가 | AI가 큰 박스 안에 카드를 넣는 구조를 직접 생성 |
| CSS 일관성 | 블록 템플릿이 보장 | 디자인 토큰 + 블록 CSS 참고로 보장 |
C_reference.png에서 증명된 것
제가 수동으로 했던 판단:
- topic 1(문제제기) + topic 2(사례) → 1영역에 통합, dark-bullet-list의 CSS 색상 사용
- 사례 2건 → 가로 2열 카드, 같은 구조로 나란히
- topic 3(핵심) → DX 큰 박스 안에 GIS/BIM/DT 카드 = 포함 관계 시각화
- "BIM ≠ DX" → 별도 강조 박스 (topic에 없는 요소를 추가)
- sidebar 용어 → 풀 정의 + 출처, card-numbered의 CSS 스타일 참고
이 판단들을 AI가 하는 것이 접근 C.
3. 프로세스 설계
기존 프로세스 (P=Q=R)
1단계: Kei 분석 (topics, relation_type, expression_hint, page_structure)
1.5단계: Kei 컨셉 구체화 (source_data)
컨테이너 계산 (비중 → px)
프리셋 선택 (sidebar-right 등)
2단계: 블록 선택 (block_selector → catalog → Kei 선택) ← 여기가 문제
3단계: 텍스트 채우기 (fill_candidates → 슬롯에 텍스트) ← 여기가 문제
4단계: CSS 조정 + 렌더링
검증: Selenium 측정
품질 게이트: 비전 모델
접근 C 프로세스
1단계: Kei 분석 (동일)
1.5단계: Kei 컨셉 구체화 (동일)
컨테이너 계산 (동일)
프리셋 선택 (동일)
2-3단계 통합: AI가 HTML 구조를 직접 생성 ← 여기가 바뀜
입력: Kei 분석 결과 + 원본 텍스트 + 디자인 토큰 + 블록 CSS 참고 + 컨테이너 스펙
출력: 각 컨테이너 영역의 HTML (슬라이드 body, sidebar, footer)
AI가 결정하는 것:
- 각 topic을 어떤 구조로 보여줄지 (불릿? 비교? 포함관계? 카드?)
- topic을 합칠지 분리할지
- 핵심 메시지를 별도 강조할지
- 텍스트를 어떻게 배치할지
AI가 참고하는 것:
- 디자인 토큰 (CSS 변수 — 색상, 폰트, 간격)
- 기존 블록의 CSS 패턴 (다크 배경, 카드 스타일, 배너 스타일 등)
- 컨테이너 크기 (px)
- expression_hint ("포함 관계 시각화", "프로세스 변화")
- 예시 슬라이드 (few-shot)
4단계: 렌더링 (AI가 생성한 HTML을 슬라이드 프레임에 삽입)
검증: Selenium 측정 (동일)
품질 게이트: 비전 모델 (동일)
변경되는 것 / 변경되지 않는 것
| 항목 | 변경 여부 |
|---|---|
| 1단계 Kei 분석 | 변경 없음 |
| 1.5단계 컨셉 구체화 | 변경 없음 |
| 컨테이너 계산 (space_allocator) | 변경 없음 |
| 프리셋 선택 | 변경 없음 |
| 2단계 블록 선택 (block_selector) | 제거 — AI가 직접 구조 결정 |
| 3단계 슬롯 채우기 (fill_candidates) | 제거 — AI가 HTML에 텍스트 직접 포함 |
| 4단계 CSS 조정 | 변경 — AI 생성 HTML을 프레임에 삽입 |
| Selenium 측정 | 변경 없음 |
| 비전 모델 품질 게이트 | 변경 없음 |
| slide-base.html | 변경 없음 |
| tokens.css, base.css | 변경 없음 |
4. AI HTML 생성의 구체적 설계
4-1. AI에게 주는 입력
1. 원본 콘텐츠 (MDX 텍스트 전체)
2. Kei 분석 결과:
- topics[] (id, title, purpose, relation_type, expression_hint, source_data)
- page_structure (본심/배경/첨부/결론 비중)
- core_message
3. 컨테이너 스펙:
- 각 역할별 높이(px), 너비(px)
- 프리셋 (sidebar-right, two-column 등)
4. 디자인 토큰 (tokens.css 전문)
5. 블록 CSS 패턴 참고 (주요 블록의 CSS만 발췌):
- 다크 배경 패턴 (.block-dark-bullets의 색상/배경)
- 카드 패턴 (.cid-card의 border/radius/padding)
- 배너 패턴 (.block-banner-grad의 gradient)
- 비교 패턴 (.block-comparison의 좌우 분할)
- 테이블 패턴 (.block-table-striped의 헤더/행)
6. 예시 슬라이드 2-3개 (few-shot):
- C_reference.png의 HTML
- hybrid_simulation의 HTML
- (다른 콘텐츠 예시)
4-2. AI에게 요구하는 출력
각 영역(body, sidebar, footer)의 HTML 조각.
슬라이드 프레임(slide-base.html)에 삽입할 수 있는 형태.
{
"body_html": "<div class=\"container-배경\">...</div><div class=\"container-본심\">...</div>",
"sidebar_html": "<div class=\"sidebar-label\">용어 정의</div><div class=\"def-item\">...</div>...",
"footer_html": "<div class=\"block-banner-grad\"><div class=\"bg-text\">...</div></div>"
}
4-3. AI HTML 생성 규칙 (프롬프트에 포함)
## 규칙
1. 원본 텍스트를 그대로 사용한다 (자유도 15-20). 축약은 공간 부족 시에만.
2. 디자인 토큰(CSS 변수)만 사용한다. 하드코딩 색상/폰트 금지.
3. 블록 CSS 패턴을 참고하되, 구조는 콘텐츠에 맞게 자유롭게 구성한다.
4. 컨테이너 높이를 초과하지 않는다.
5. expression_hint를 반드시 반영한다:
- "포함 관계" → 큰 박스 안에 작은 카드
- "프로세스 변화" → Before→After 구조
- "독립 사례 나열" → 가로 카드 비교
6. topic을 합치거나 분리할 수 있다 (page_structure의 역할 기준).
7. 핵심 메시지(core_message)는 별도 강조 요소로 만들 수 있다.
4-4. 품질 보장 (5중 방어)
Layer 1: 디자인 토큰 제약 (CSS 변수만 사용)
Layer 2: 컨테이너 크기 제약 (px 명시)
Layer 3: HTML 정화 (nh3 — script 태그 등 제거)
Layer 4: Selenium 측정 (overflow 감지)
Layer 5: 비전 모델 품질 게이트 (시각적 평가)
5. 구현 스텝
| 스텝 | 내용 | 파일 | 비고 |
|---|---|---|---|
| R'-1 | 디자인 토큰 + 블록 CSS 패턴을 프롬프트용 텍스트로 추출 | 신규 src/design_tokens.py |
tokens.css + 주요 블록 CSS 발췌 |
| R'-2 | few-shot 예시 슬라이드 정리 (2-3개) | data/examples/ |
C_reference.html, hybrid_simulation.html |
| R'-3 | AI HTML 생성 함수 구현 | 신규 src/html_generator.py |
Kei 분석 + 토큰 + 예시 → HTML 생성 |
| R'-4 | pipeline.py 2-3단계를 html_generator로 교체 | src/pipeline.py |
block_selector, fill_candidates 호출 제거 |
| R'-5 | 렌더러에 AI 생성 HTML 삽입 함수 추가 | src/renderer.py |
기존 render_slide와 별도로 render_slide_from_html 추가 |
| R'-6 | HTML 정화 + 토큰 위반 검증 | 신규 src/html_validator.py |
nh3 + tinycss2 |
| R'-7 | 테스트 (2개 콘텐츠로 검증) | scripts/test_phase_r_prime.py |
DX 이해 + DX 목표 |
의존 관계
R'-1 (토큰 추출) ──→ R'-3 (HTML 생성)
R'-2 (예시 정리) ──→ R'-3
R'-3 ──→ R'-4 (파이프라인 교체) ──→ R'-7 (테스트)
R'-3 ──→ R'-5 (렌더러 추가)
R'-6 (검증) ←── 독립, R'-4와 병렬
6. pipeline.py 변경 상세 — 정확히 어디가 교체되는가
유지되는 코드 (1단계 ~ 컨테이너 계산: 줄 96~165)
# 줄 96~109: 1단계 Kei 분석 — 유지
analysis = await _retry_kei(classify_content, content)
_save_step(run_dir, "step1_analysis.json", analysis)
# 줄 111~120: 1.5단계 컨셉 구체화 — 유지
analysis = await refine_concepts(content, analysis)
_save_step(run_dir, "step1b_concepts.json", ...)
# 줄 122~140: 제목 중복 검증, 이미지 측정 — 유지
# 줄 142~164: 컨테이너 스펙 계산 — 유지
preset_name = select_preset(analysis)
preset = LAYOUT_PRESETS.get(preset_name, {})
container_specs = calculate_container_specs(...)
_save_step(run_dir, "step1c_containers.json", ...)
제거되는 코드 (2-3단계: 줄 166~339)
# 줄 166~207: Phase Q 블록 선택 — 전체 제거
# block_selector.select_block_candidates()
# select_fallback_candidates()
# calculate_budgets_for_candidates()
# 줄 209~257: Kei 블록 선택 — 전체 제거
# select_block_for_topics()
# selected_blocks 딕셔너리 생성
# finalize_block_specs()
# 줄 259~298: layout_concept 조립 — 전체 제거
# final_blocks 리스트, sidebar label, 역할 순서 배치
# 줄 300~339: fill_candidates 호출 — 전체 제거
# topic별 fill_candidates()
# 결과 검증
교체되는 코드 (R'-4에서 신규 작성)
# 2-3단계 통합: AI HTML 생성 (줄 166~ 교체)
yield {"event": "progress", "data": "2/5 슬라이드 HTML 생성 중..."}
from src.html_generator import generate_slide_html
from src.html_validator import validate_html
# AI가 HTML 직접 생성
generated = await generate_slide_html(
content=content,
analysis=analysis,
container_specs=container_specs,
preset=preset,
)
# HTML 정화 + 토큰 위반 검증
validated_html = validate_html(generated)
_save_step(run_dir, "step2_generated.json", {
"body_html_length": len(generated.get("body_html", "")),
"sidebar_html_length": len(generated.get("sidebar_html", "")),
"footer_html_length": len(generated.get("footer_html", "")),
})
유지되는 코드 (4단계 이후: 줄 341~)
# 줄 341~350: 4단계 렌더링 — 유지하되 render_slide → render_slide_from_html로 변경
html = render_slide_from_html(generated, analysis, preset)
_save_step(run_dir, "step4_rendered.html", html)
# 줄 352~446: Selenium 측정, overflow 감지, 수학적 조정 — 유지
# 단, overflow 시 텍스트 압축(fill_content 호출, 줄 442)은 제거
# 대신 AI HTML 재생성 요청
# 줄 448~474: 비전 모델 품질 게이트 — 유지
# 줄 476~483: 이미지 삽입, final.html 저장 — 유지
_adjust_design (줄 490~589) — 제거 또는 변경
현재: layout_concept의 블록별 텍스트 양을 보고 CSS 변수 조정
R': AI가 HTML 생성 시 이미 CSS를 포함하므로, 별도 CSS 조정 단계 불필요
→ 제거하거나, AI 생성 HTML에 대한 보조 조정으로 역할 축소
_review_balance, _apply_adjustments (줄 592~730) — 변경
현재: 블록 기반 layout_concept를 검수/조정
R': AI 생성 HTML을 검수. 조정 시 block_selector/fill_candidates가 아닌 html_generator 재호출
줄 729의 fill_content() 호출 → 제거
_build_overflow_context, _convert_kei_judgment (줄 733~800) — 변경
현재: layout_concept의 블록 데이터에서 overflow 컨텍스트 추출
R': AI 생성 HTML에서 직접 추출하도록 변경
7. 다른 파일에 대한 영향 (충돌/회귀 체크)
영향 없음 (건드리지 않음)
| 파일 | 이유 |
|---|---|
src/kei_client.py — classify_content, refine_concepts |
1단계에서 호출. R'에서 변경 없음 |
src/kei_client.py — vision_quality_gate |
품질 게이트. R'에서 변경 없음 |
src/space_allocator.py — calculate_container_specs |
컨테이너 계산. R'에서 변경 없음 |
src/design_director.py — select_preset, LAYOUT_PRESETS |
프리셋 선택. R'에서 변경 없음 |
src/slide_measurer.py |
Selenium 측정. R'에서 변경 없음 |
src/config.py |
설정. 변경 없음 |
src/sse_utils.py |
SSE 스트리밍. 변경 없음 |
src/image_utils.py |
이미지 크기 측정. 변경 없음 |
src/main.py |
FastAPI 엔드포인트. generate_slide 호출은 동일 |
static/index.html |
프론트엔드. 변경 없음 |
templates/slide-base.html |
슬라이드 프레임. 변경 없음 |
static/tokens.css, static/base.css |
디자인 토큰. 변경 없음 (프롬프트에서 읽기만 함) |
templates/blocks/*.html |
38개 블록. 변경 없음 (CSS 참고용으로만 유지) |
templates/catalog.yaml |
변경 없음 (프롬프트에서 CSS 패턴 인덱스로 참고만) |
변경되는 파일
| 파일 | 변경 내용 | 기존 코드 영향 |
|---|---|---|
src/pipeline.py |
줄 166~339 교체 (블록 선택+채우기 → html_generator 호출) | 2-3단계만 교체, 나머지 유지 |
src/pipeline.py |
_adjust_design 제거 또는 축소 | 4단계 CSS 조정 불필요 |
src/pipeline.py |
_apply_adjustments에서 fill_content 호출 제거 | overflow 시 html_generator 재호출 |
src/renderer.py |
render_slide_from_html() 신규 함수 추가 |
기존 render_slide() 변경 없음 (하위 호환) |
신규 파일
| 파일 | 역할 |
|---|---|
src/html_generator.py |
핵심 — Kei 분석 + 토큰 + 예시 → AI HTML 생성 |
src/design_tokens.py |
tokens.css + 블록 CSS 패턴을 프롬프트용 텍스트로 추출 |
src/html_validator.py |
nh3 정화 + CSS 토큰 위반 검증 |
data/examples/C_reference.html |
few-shot 예시 1 |
data/examples/hybrid_simulation.html |
few-shot 예시 2 |
scripts/test_phase_r_prime.py |
R' 테스트 스크립트 |
호출하면 안 되는 것 (자기 검증)
| 함수 | 위치 | 이유 |
|---|---|---|
select_block_candidates() |
block_selector.py |
블록 선택 시스템 — R'에서 제거 |
select_fallback_candidates() |
block_selector.py |
동일 |
select_block_for_topics() |
kei_client.py |
블록 선택 AI — R'에서 제거 |
fill_candidates() |
content_editor.py |
슬롯 채우기 — R'에서 제거 |
fill_content() |
content_editor.py |
동일 |
finalize_block_specs() |
space_allocator.py |
블록 스펙 — 블록 없으므로 불필요 |
calculate_budgets_for_candidates() |
space_allocator.py |
블록 예산 — 블록 없으므로 불필요 |
호출해야 하는 것 (유지)
| 함수 | 위치 | 이유 |
|---|---|---|
classify_content() |
kei_client.py |
1단계 Kei 분석 |
refine_concepts() |
kei_client.py |
1.5단계 컨셉 구체화 |
calculate_container_specs() |
space_allocator.py |
컨테이너 px 계산 |
select_preset() |
design_director.py |
프리셋 선택 |
measure_rendered_heights() |
slide_measurer.py |
Selenium 측정 |
capture_slide_screenshot() |
slide_measurer.py |
스크린샷 캡처 |
vision_quality_gate() |
kei_client.py |
비전 모델 품질 게이트 |
generate_slide_html() |
html_generator.py (신규) |
AI HTML 생성 |
validate_html() |
html_validator.py (신규) |
HTML 정화+검증 |
render_slide_from_html() |
renderer.py (신규 함수) |
AI HTML → 슬라이드 프레임 삽입 |
8. 자기 검증 체크리스트
구현 시작 전 반드시 확인:
- block_selector.py에서 블록을 "선택"하는 코드를 호출하고 있는가? → 호출하면 안 됨
- fill_candidates/fill_content로 "슬롯에 텍스트를 채우는" 코드를 호출하고 있는가? → 호출하면 안 됨
- finalize_block_specs/calculate_budgets_for_candidates를 호출하고 있는가? → 호출하면 안 됨
- AI가 HTML 구조를 결정하고 있는가, 블록 템플릿이 구조를 결정하고 있는가? → AI가 결정해야 함
- 기존 코드를 "수정"하는 것인가, "교체"하는 것인가? → 2-3단계는 교체
- C_reference.png 수준의 결과가 나올 수 있는 구조인가? → topic 합침, 포함 관계, 핵심 메시지 분리가 가능해야 함
- _adjust_design에서 블록 기반 로직을 사용하고 있는가? → 사용하면 안 됨
- _apply_adjustments에서 fill_content를 호출하고 있는가? → 호출하면 안 됨
9. 기대 효과
| 지표 | Phase R (실패) | Phase R' (목표) |
|---|---|---|
| 결과물 수준 | 34점 (블록 선택+슬롯 한계) | C_reference.png 수준 (70점+) |
| 구조 결정 주체 | 블록 템플릿 | AI (콘텐츠 기반) |
| topic 합침/분리 | 불가 | 가능 |
| 포함 관계 시각화 | 해당 블록 없으면 불가 | AI가 직접 구성 |
| 원본 텍스트 보존 | 편집자 의존 (축약됨) | AI가 원본 직접 삽입 |
| CSS 일관성 | 블록 템플릿 보장 | 디자인 토큰 + 블록 CSS 참고 + 검증 |
10. 회귀 방지 — Phase P=Q=R 반복 금지
이 Phase에서 절대 하면 안 되는 것
- block_selector.py의 select_block_candidates를 호출하면 안 됨 — 블록 "선택" 시스템 회귀
- content_editor.py의 fill_candidates/fill_content를 호출하면 안 됨 — "슬롯 채우기" 회귀
- catalog.yaml에서 블록을 매칭하면 안 됨 — 블록 매칭 회귀
- variant를 추가하면 안 됨 — Phase R의 실패 패턴 회귀
- "최소 변경"으로 기존 코드 위에 패치하면 안 됨 — P=Q=R 반복의 원인
이 Phase에서 반드시 해야 하는 것
- html_generator.py에서 AI가 HTML 구조를 직접 생성 — 콘텐츠가 구조를 결정
- 블록 CSS는 참고만 — "선택"이 아닌 "참고"
- pipeline.py 줄 166~339를 교체 — 패치가 아닌 교체
- C_reference.png와 동일 수준의 결과를 자동으로 생성 — 이것이 합격 기준