Files
C.E.L_Slide_test2/docs/history/PHASE-W-PLAN.md
kyeongmin c42e01f060 문서 정리: Phase 히스토리 md를 docs/history/로 이동 + 오래된 테스트/에셋 정리
- 루트의 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>
2026-04-13 10:56:23 +09:00

274 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase W — 실행 계획 (Task별 방향 + 방법)
> 작성일: 2026-04-03
> 상위 문서: PHASE-W.md
---
## W-1: space_allocator — weight 비율 초기 배정
### W-1-1: zone_budget을 weight 비율로 계산
**현재:** `zone_budget = zone_info.get("budget_px")` → 프리셋 490px 고정
**방향:** `zone_budget = total_available × zone_weight_sum / all_weight_sum`
**파일:** `src/space_allocator.py``calculate_container_specs()` 내부
**방법:**
- 전체 가용 높이 = slide_height - padding×2 - gap×2 - header
- 각 zone의 weight 합을 구함 (body zone = 배경+본심 weight, sidebar = 첨부 weight 등)
- 전체 weight 합 대비 비율로 zone_budget 계산
- 이전에 구현했던 코드를 다시 적용 (173113 run에서 동작 확인됨)
**검증:** weight 합 1.0일 때 모든 컨테이너 높이 합 출력하여 전체 가용의 95% 이상인지 확인
### W-1-2: 전체 공간 100% 사용
**방향:** W-1-1이 해결되면 자동으로 해결
**검증:** `stage_1_5a_context.json`에서 모든 컨테이너 height_px 합산 ≥ 전체 가용 × 0.95
### W-1-3: 시선 흐름 배치 좌표
**현재:** `_calc_coords()`가 배경→상단좌, 본심→중앙좌, 첨부→우측, 결론→하단으로 배치
**방향:** 현재 코드 유지 (이미 올바름)
**검증:** `stage_1_8_filled.html`에서 배경이 상단, 본심이 중앙, 첨부가 우측, 결론이 하단에 위치
---
## W-2: block_assembler — 공통 조립 함수 완성
### W-2-1: font_hierarchy override
**현재:** `_override_font()` 함수가 블록 CSS의 font-size를 font_hierarchy로 조정
**방향:** 현재 코드 유지
**검증:** filled HTML에서 첨부 영역의 font-size가 sidebar 값(9-11px)을 초과하지 않음
### W-2-2: 팝업 링크 인접 배치
**현재:** `_parse_structured_text()`에서 `[팝업: 제목]`을 이전 불릿 텍스트에 `[제목→]`으로 붙임
**방향:** 현재 코드 유지
**검증:** filled HTML에서 `[혼용 대표 사례→]`가 별도 줄이 아니라 텍스트 옆에 붙어있음
### W-2-3: sidebar 상단 라벨
**현재:** `_assemble_card_numbered()`에서 `topic.title`을 라벨로 추가
**방향:** 현재 코드 유지
**검증:** filled HTML의 첨부 영역 상단에 꼭지 title이 보임
### W-2-4: 카드 indent 파싱
**현재:** `_assemble_card_numbered()`에서 indent=0만 카드 제목, indent=1은 설명
**방향:** 현재 코드 유지
**검증:** 첨부에 건설산업/BIM/DX 3개 카드가 분리되고, 하위 설명이 각 카드 안에 있음
### W-2-5: 카드 불릿 간격
**현재:** CSS override에서 `white-space: pre-line → normal` 변환
**방향:** 현재 코드 유지
**검증:** 첨부 카드 내 불릿과 불릿 사이에 빈 줄(엔터)이 없음
### W-2-6: 실제 이미지 사용
**현재:** `has_real_image` 분기로 실제 이미지 있으면 SVG 레이아웃, 없으면 텍스트만
**방향:** 수정 필요 — 현재 `_assemble_svg_layout()``design_reference_html`에서 SVG를 추출. 이걸 `ctx.slide_images`의 실제 이미지(base64)로 교체
**파일:** `src/block_assembler.py``_assemble_svg_layout()`
**방법:**
- `ctx.slide_images`에서 해당 이미지의 base64 데이터를 가져옴
- `<img src="data:image/png;base64,{b64}" />` 형태로 삽입
- SVG viewBox/gradient 하드코딩 대신 실제 이미지 사용
**검증:** filled HTML에 `<img src="data:image/png;base64,` 패턴이 있고, SVG 태그가 없음
### W-2-7: filled/assembled 통일
**현재:** `_gen_stage_1_8_filled()``assemble_slide_html()` 호출
**방향:** assembled(stage_2_code_assembled)도 같은 함수 호출하도록 `assemble_stage2.py` 수정 또는 제거
**검증:** filled와 assembled가 같은 HTML 구조를 가짐 (diff로 확인)
### W-2-8: 팝업 마크다운 테이블 변환
**현재:** `mdx_normalizer.py``_extract_popup()`에서 `_convert_md_table_to_html()` 호출
**방향:** 현재 코드 유지
**검증:** `stage_0_context.json`의 popups에서 "DX와 BIM의 구분" 팝업에 `<table>` 태그가 있고 `|` 마크다운이 없음
---
## W-3: filled → Selenium 측정 연결
### W-3-1: .slide 클래스
**현재:** `assemble_slide_html()`의 최외곽 div에 `class="slide"` 있음
**방향:** 현재 코드 유지
**검증:** filled HTML에서 `class="slide"` 존재 확인
### W-3-2: area-* 클래스
**현재:** 각 역할 컨테이너에 `area-body`, `area-sidebar`, `area-footer` 클래스 있음
**방향:** 현재 코드 유지
**검증:** filled HTML에서 `area-body`, `area-sidebar`, `area-footer` 존재 확인
### W-3-3: Selenium 측정 정상 동작
**현재:** 173113 run에서 `{'error': 'slide not found'}` 발생 (당시 .slide 클래스 없었음)
**방향:** W-3-1, W-3-2가 해결되면 자동 해결
**방법:** filled HTML을 `measure_rendered_heights()`에 넣고 정상 결과 반환 확인
**검증:** 반환값에 `zones.sidebar.scrollHeight`, `zones.body.scrollHeight` 등이 있고 `error` 키가 없음
### W-3-4: 시각화 순서 (before → filled → after)
**현재:** `step_visualizer.py`의 dispatch에서 blocks → filled → fit_before → fit_after 순서
**방향:** before(빈 컨테이너 크기) → filled(블록+텍스트 채운 상태) → after(조정된 크기) 순서
**파일:** `src/step_visualizer.py``generate_step_html()`
**방법:**
- `stage_1_8` dispatch 순서를 `fit_before → filled → fit_after`로 변경
- fit_before는 빈 컨테이너 크기만 보여줌 (부족/여유 판단 없이)
- filled는 블록+텍스트 채운 상태
- fit_after는 조정 후 컨테이너 크기
**검증:** steps 폴더에 3개 파일이 순서대로 있고, before의 크기 → filled의 넘침 → after의 변경이 시각적으로 확인 가능
---
## W-4: 측정 결과 기반 조정 판단
### W-4-1: sidebar overflow → 확장
**현재:** pipeline.py Stage 1.8에 sidebar 확장 코드 있음
**방향:** 현재 코드 유지 (Selenium 측정이 동작하면 자동으로 발동)
**검증:** sidebar scrollHeight > clientHeight일 때 `stage_1_8_context.json`의 첨부 height_px가 scrollHeight 이상으로 증가
### W-4-2: body overflow → 재배분
**현재:** `redistribute()` 함수가 body zone 내에서 배경↔본심 재배분
**방향:** 현재 코드 유지
**검증:** body overflow 시 배경 또는 본심의 height_px가 변경됨
### W-4-3: 재배분 후에도 overflow → Kei 에스컬레이션
**현재:** `needs_escalation=True`일 때 `call_kei_fit_escalation()` 호출
**방향:** 현재 코드 유지
**검증:** `enhancement_result.kei_decisions`에 Kei 응답이 저장됨
### W-4-4: Kei trim/popup 결정 실제 적용
**현재:** Kei 결정을 받지만 실제 반영 안 됨
**방향:** 새로 구현
**파일:** `src/pipeline.py` Stage 1.8 내부 + 새 함수
**trim 구현 방법:**
- Kei가 `{"action": "trim", "detail": "150자로 축약"}`을 반환하면
- 해당 role의 topic structured_text를 **Kei/Sonnet에게 축약 요청** (AI 판단 — 어떤 문장이 덜 중요한지는 AI만 알 수 있음)
- 프롬프트: "다음 텍스트를 N자 이내로 축약하라. 불릿 구조 유지. 핵심 85% 보존."
- 축약된 텍스트로 structured_text 교체
- 하드코딩 없음 — 어떤 콘텐츠든 AI가 판단
- **도구:** anthropic SDK (이미 있음), Kei API /api/direct
**popup 구현 방법:**
- Kei가 `{"action": "popup", "detail": "상세 정의를 팝업으로"}`를 반환하면
- 해당 role의 structured_text를 **Kei/Sonnet에게 분리 요청** ("요약 vs 상세" 판단)
- 프롬프트: "다음 콘텐츠를 슬라이드 요약(2-3줄)과 팝업 상세로 분리하라."
- 요약은 structured_text에, 상세는 별도 팝업 HTML로 저장
- 슬라이드에는 요약 + `[상세보기→]` 링크
- 하드코딩 없음 — 어떤 콘텐츠든 AI가 요약/상세를 판단
- **도구:** anthropic SDK, 팝업 HTML 템플릿 (pipeline.py Stage 5에 이미 있음)
**검증:** trim 후 structured_text 길이가 줄어들고, popup 후 팝업 HTML 파일이 생성됨
### W-4-5: Kei restructure → 컨테이너 직접 변경
**현재:** `redistribute()` 재실행만 됨
**방향:** Kei가 "본심에 363px 보장"하면 직접 height_px 변경
**파일:** `src/pipeline.py` Stage 1.8 내부
**방법:**
- Kei 결정에서 구체적 px 값을 파싱 (정규식으로 숫자 추출)
- 해당 role의 height_px를 직접 설정
- 다른 role에서 부족분을 **weight 역비례**로 차감 (중요도 낮은 곳에서 더 많이)
- 최소 높이(60px) 보장
- 총합이 전체 가용 초과하지 않도록 검증
- 하드코딩 없음 — 순수 산술, 어떤 role이든 동작
- **도구:** Python 산술 (외부 라이브러리 불필요)
**검증:** restructure 후 해당 role의 height_px가 Kei가 지정한 값으로 변경되고, 총합이 전체 가용 이하
### W-4-6: after 컨테이너 저장
**현재:** `stage_1_8_context.json`에 containers 저장됨
**방향:** 현재 코드 유지 (W-4-1~5의 결과가 containers에 반영되면 자동 저장)
**검증:** `stage_1_8_context.json`의 containers가 before와 다름
### W-4-7: Kei 보강 검토 호출
**현재:** `call_kei_enhancement_review()` 함수 있고 pipeline.py에서 호출
**방향:** 현재 코드 유지
**검증:** `enhancement_result`에 Kei 보강 검토 결과가 저장됨 (approve/modify/reject)
---
## W-5: after 기반 최종 조립 + 검증
### W-5-1: stage_2가 after 컨테이너 사용
**현재:** stage_2_context.json의 containers == stage_1_8_context.json의 containers (확인됨)
**방향:** 현재 코드 유지
**검증:** 두 JSON의 containers 비교 — 일치
### W-5-2: overflow 없음 확인
**현재:** Stage 4에서 Selenium 측정. Vision 모델 ID 404 에러
**방향:** Vision 모델 ID를 `claude-sonnet-4-20250514`로 변경 (vision 지원, 비용 효율)
**파일:** `src/kei_client.py` — 3곳
**방법:** 모델 ID 문자열 교체
**검증:** Stage 4에서 모든 zone의 excess_px ≤ 0
### W-5-3: 텍스트 85% 보존 검증
**현재:** 검증 로직 없음
**방향:** 새로 구현
**파일:** `src/pipeline.py` Stage 4 또는 Stage 5
**방법:**
- final.html에서 HTML 태그 제거하여 순수 텍스트 추출 (Python stdlib `html.parser`)
- 각 role의 structured_text와 문자 3-gram 겹침 비교
- 85% 이상이면 PASS
- 하드코딩 없음 — 문자열 비교만, 어떤 콘텐츠든 동작
- **도구:** Python stdlib만 (html.parser, re). 외부 NLP 불필요
**검증:** 검증 함수가 각 role별 보존율을 반환하고, 모든 role이 85% 이상
---
## 의존 관계
```
W-1-1 → W-1-2 (자동)
W-1 + W-2 → W-3 (filled 생성 + 측정)
W-3 → W-4 (측정 결과로 판단)
W-4 → W-5 (after 기반 최종)
W-2 내부: 1~8 독립적으로 병행 가능
W-4 내부: 1→2→3→4/5 순차, 6/7 독립
```
---
## 필요 도구/라이브러리
| 도구 | 용도 | 상태 |
|------|------|------|
| Selenium + Chrome headless | filled 측정 (W-3) | ✅ 설치됨, 동작 확인 |
| anthropic SDK | Kei trim/popup (W-4-4), Vision (W-5-2) | ✅ 설치됨 |
| httpx | Kei API 호출 | ✅ 설치됨 |
| Kei API (localhost:8000) | 에스컬레이션, 보강 검토 | ✅ 동작 확인 |
| Python stdlib (html.parser, re) | 텍스트 보존 검증 (W-5-3) | ✅ 내장 |
| Jinja2 | 블록 템플릿 렌더링 | ✅ 설치됨 |
**추가 설치 필요 없음.**
---
## 실행 순서
```
Phase 1: W-1 (weight 비율) — 기반
Phase 2: W-2 (공통 조립 함수) — W-1과 병행 가능
Phase 3: W-3 (Selenium 연결) — W-1 + W-2 필요
Phase 4: W-4 (판단 로직) — W-3 필요
Phase 5: W-5 (최종 검증) — W-4 필요
각 Phase 완료 후 파이프라인 실행하여 검증.
```