Files
C.E.L_Slide_test2/README.md
kyeongmin 1f7579cf64 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>
2026-04-06 05:00:52 +09:00

304 lines
14 KiB
Markdown
Raw 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.
# Kei Design Agent
콘텐츠를 시각적으로 구조화된 슬라이드 HTML(1280×720px, 16:9)로 변환하는 AI 파이프라인.
## 개요
텍스트/MDX 콘텐츠를 입력하면:
1. Kei 실장(Opus)이 정보 구조와 비중을 판단하고
2. 코드가 컨테이너 크기를 계산하고
3. 블록을 선택하고
4. 콘텐츠-컨테이너 적합성을 검증하고
5. AI(Sonnet)가 블록 디자인을 참고하여 HTML을 생성하고
6. 코드가 슬라이드 프레임에 조립하고
7. 측정+비전 모델로 검증합니다
---
## 파이프라인 (10단계)
```
MDX 원본
[Stage 0] MDX 정규화 (코드)
[Stage 1A] 꼭지 추출 + 영역 배정 (Kei API / Opus)
[Stage 1B] 컨셉 구체화 (Kei API / Opus)
[Stage 1.5a] 컨테이너 초기 계산 (코드)
[Stage 1.7] 블록 선택 (코드)
[Stage 1.8] 적합성 검증 + 재배분 + 보강 (코드 + Kei 에스컬레이션)
[Stage 1.5b] 디자인 예산 재계산 (코드)
[Stage 2] HTML 생성 (영역별 개별 호출) (Claude Sonnet)
[Stage 3] 렌더링 조립 + 후처리 (코드)
[Stage 4] 측정 + 품질 검증 (Selenium + Opus Vision)
검증 통과 시 → final.html 저장 + 팝업 분리 (파일 출력)
```
※ Stage 4 이후의 파일 저장은 별도 Stage가 아닌 후처리입니다.
---
## 단계별 상세
### Stage 0: MDX 정규화
| 항목 | 내용 |
|------|------|
| **목적** | 원본 MDX에서 JSX/frontmatter를 제거하고, 섹션/팝업/이미지/테이블로 분리 |
| **적용기술** | 코드 (`normalize_mdx_content()`) |
| **인풋** | 원본 MDX 문자열 |
| **아웃풋** | `normalized` — clean_text, title, sections[], popups[], images[], tables[] |
| **연계** | → Stage 1A가 clean_text를 Kei에게 전달 |
### Stage 1A: 꼭지 추출 + 영역 배정
| 항목 | 내용 |
|------|------|
| **목적** | 콘텐츠에서 핵심 파트(꼭지)를 식별하고, 슬라이드의 어떤 영역(배경/본심/첨부/결론)에 배치할지 결정 |
| **적용기술** | Kei API (`classify_content()`) |
| **인풋** | normalized.clean_text |
| **아웃풋** | `topics[]` (id, title, purpose, layer, relation_type, expression_hint), `page_structure` (role별 topic_ids, weight) |
| **연계** | → Stage 1B가 각 꼭지를 구체화 |
### Stage 1B: 컨셉 구체화
| 항목 | 내용 |
|------|------|
| **목적** | 각 꼭지에 실제 원본 텍스트(source_data)와 요약(summary)을 매핑 |
| **적용기술** | Kei API (`refine_concepts()`) |
| **인풋** | topics + clean_text |
| **아웃풋** | `topics` 업데이트 — source_data, summary 추가 |
| **연계** | → Stage 1.5a가 텍스트 양을 기반으로 컨테이너 비율 계산 |
### Stage 1.5a: 컨테이너 초기 계산
| 항목 | 내용 |
|------|------|
| **목적** | 폰트 위계 확정 + 슬라이드 내 영역별 컨테이너 크기(px) 계산 + 프리셋 선택 |
| **적용기술** | 코드 (`calculate_font_hierarchy()`, `calculate_dynamic_ratio()`, `calculate_container_specs()`) |
| **인풋** | topics, page_structure (weight), preset |
| **아웃풋** | `font_hierarchy` (key_msg/core/bg/sidebar px), `container_ratio` (71:29 등), `containers` (role별 width_px, height_px), `preset` |
| **연계** | → Stage 1.7이 컨테이너 크기를 보고 블록 선택 |
### Stage 1.7: 블록 선택
| 항목 | 내용 |
|------|------|
| **목적** | 각 꼭지의 relation_type + expression_hint + 컨테이너 크기로 적합한 블록 결정. 같은 영역 꼭지들의 layer가 다르면 주종관계 판단 (블록 1개로 합침) |
| **적용기술** | 코드 (`select_and_generate_references()`) — catalog.yaml 기반 결정론적 매칭 |
| **인풋** | topics, containers, page_structure |
| **아웃풋** | `references` — role별 block_id, variant, design_reference_html, topic_id, is_hierarchical, supporting_topic_ids |
| **연계** | → Stage 1.8이 선택된 블록+콘텐츠가 컨테이너에 맞는지 검증 |
### Stage 1.8: 적합성 검증 + 재배분 + 보강 + 서브 컨테이너
| 항목 | 내용 |
|------|------|
| **목적** | 콘텐츠가 컨테이너에 들어가는지 검증 → 안 맞으면 재배분 → 여전히 안 되면 Kei 에스컬레이션 → 여유 공간에 보충 콘텐츠 → 서브 컨테이너 배치 계산 |
| **적용기술** | 코드 (`calculate_fit()`, `redistribute()`, `analyze_enhancements()`, `apply_enhancements()`, `calculate_sub_layout()`) + Kei API (에스컬레이션 시 `call_kei_fit_escalation()`) |
| **인풋** | topics, containers, references, font_hierarchy, normalized, core_message |
| **아웃풋** | `containers` (재배분된 height_px), `fit_result` (role별 fit_status, redistribution), `enhancement_result` (V-7 subordinate_treatments, V-8 supplement_blocks, V-9 emphasis_blocks, V-10 bold_keywords, V-4 kei_decisions), `sub_layouts` (role별 서브 컨테이너 name/width/height, table_rows) |
| **내부 흐름** | Step 1: 필요 높이 계산 → Step 2: 재배분 → Step 3: Kei 에스컬레이션 → Step 4-5: 보강 분석+적용 → Step 6: fit 재검증 → Step 7: 서브 컨테이너 배치 → Step 8: 확정 |
| **연계** | → Stage 1.5b가 재배분된 크기로 디자인 예산 재계산, → Stage 2가 sub_layouts + enhancements를 프롬프트에 반영 |
### Stage 1.5b: 디자인 예산 재계산
| 항목 | 내용 |
|------|------|
| **목적** | 재배분된 컨테이너 크기 + 선택된 블록 schema 기준으로 영역별 가용 공간 계산 |
| **적용기술** | 코드 (`calculate_design_budget()`) |
| **인풋** | containers (재배분 후), references (블록 schema) |
| **아웃풋** | `containers` 업데이트 — design_budget (available_height_px, available_width_px, fits) |
| **연계** | → Stage 2가 design_budgets를 프롬프트에 포함 |
### Stage 2: HTML 생성 (영역별 개별 호출)
| 항목 | 내용 |
|------|------|
| **목적** | page_structure에 존재하는 각 역할(배경/본심/첨부/결론)의 HTML을 **영역별 개별 Sonnet 호출**로 생성. 블록 디자인을 참고하되 콘텐츠가 구조를 결정 (Phase R' 방식) |
| **적용기술** | Claude Sonnet API — 영역당 1회 호출 (`build_area_prompt()``_call_claude()`) |
| **인풋** | raw_content, topics, containers, font_hierarchy, references (design_reference_html), sub_layouts (서브 컨테이너 치수), enhancements (V-4~V-10 지시), design_budgets |
| **호출 흐름** | Sonnet(배경) → bg_html, Sonnet(본심) → core_html, Sonnet(첨부) → sidebar_html, Sonnet(결론) → footer_html. 해당 역할에 꼭지가 없으면 스킵. body_html = bg_html + spacer + core_html |
| **아웃풋** | `generated_html` — body_html, sidebar_html, footer_html |
| **프롬프트에 포함되는 것** | 서브 컨테이너 레이아웃 제약, 디자인 레퍼런스 HTML (블록 CSS 참고), Kei 에스컬레이션 결정, 종속 꼭지 처리 지시, 보충 블록 지시, 강조 문장, bold 키워드, 폰트/컨테이너 크기 제약 |
| **연계** | → Stage 3이 영역별 HTML을 슬라이드 프레임에 배치 |
### Stage 3: 렌더링 조립 + 후처리
| 항목 | 내용 |
|------|------|
| **목적** | 생성된 HTML 조각을 CSS Grid 슬라이드 프레임에 삽입 + 후처리 (폰트 캡핑, overflow 제거, sidebar width 조정, bold 변환) |
| **적용기술** | 코드 (`render_slide_from_html()`) |
| **인풋** | generated_html, preset (grid_areas, grid_columns), font_hierarchy, container_ratio |
| **아웃풋** | `rendered_html``final.html` 파일 저장 |
| **연계** | → Stage 4가 렌더링 결과를 측정+검증 |
### Stage 4: 품질 검증
| 항목 | 내용 |
|------|------|
| **목적** | Selenium으로 실제 브라우저 렌더링 후 overflow 측정 + Opus Vision으로 시각적 품질 평가 |
| **적용기술** | Selenium (`measure_rendered_heights()`) + Claude Opus Vision (`vision_quality_gate()`) |
| **인풋** | rendered_html |
| **아웃풋** | `measurement` (zone별 clientHeight, scrollHeight, overflow, excess_px), `quality_score` |
| **연계** | 파이프라인 완료. overflow 시 경고 포함하여 진행 |
---
## 중간 산출물
파이프라인 실행마다 `data/runs/{timestamp}/`에 단계별 결과가 저장된다.
### JSON Context (Stage별 누적 상태)
| 파일 | Stage | 내용 |
|------|-------|------|
| `stage_0_context.json` | 0 | normalized (섹션, 팝업, 이미지) |
| `stage_1a_context.json` | 1A | topics, page_structure |
| `stage_1b_context.json` | 1B | topics (source_data 추가) |
| `stage_1_5a_context.json` | 1.5a | font_hierarchy, containers, ratio |
| `stage_1_7_context.json` | 1.7 | references (블록 선택 결과) |
| `stage_1_8_context.json` | 1.8 | fit_result, enhancements, sub_layouts |
| `stage_1_5b_context.json` | 1.5b | containers (design_budget 추가) |
| `stage_2_context.json` | 2 | generated_html |
| `stage_3_context.json` | 3 | (rendered_html은 final.html로 별도 저장) |
| `stage_4_context.json` | 4 | measurement, quality_score |
| `final_context.json` | 최종 | 전체 context |
### HTML 시각화 (`steps/` 폴더)
| 파일 | Stage | 내용 |
|------|-------|------|
| `stage_0.html` | 0 | 섹션/팝업/이미지 목록 |
| `stage_1a.html` | 1A | 꼭지 테이블 (purpose, layer, 영역) |
| `stage_1b.html` | 1B | 꼭지 + source_data + summary |
| `stage_1_5a.html` | 1.5a | 빈 컨테이너 (1280×720) |
| `stage_1_5a_content.html` | 1.5a | 컨테이너에 콘텐츠 배치 |
| `stage_1_5b.html` | 1.5b | 디자인 예산 (available height/width) |
| `stage_1_7.html` | 1.7 | 블록 선택 표시 |
| `stage_1_8_fit_before.html` | 1.8 | 적합성 (재배분 전) |
| `stage_1_8_fit_after.html` | 1.8 | 재배분 후 + 보강 |
| `stage_1_8_blocks.html` | 1.8 | SLOT 구조 + 블록 디자인 + 주종관계 (1280×720) |
| `stage_2.html` | 2 | 영역별 Sonnet 출력을 실제 렌더링 (역할별 개별 확인) |
| `stage_3.html` | 3 | 영역을 합쳐 슬라이드 프레임에 배치한 결과 (1280×720 실제 렌더링) |
| `stage_4.html` | 4 | 측정 결과 + 품질 점수 |
---
## 핵심 원칙
1. **콘텐츠가 구조를 결정** — 블록 CSS는 참고만. AI가 콘텐츠 전달 의도를 보고 HTML 구조 결정 (Phase R')
2. **하드코딩 금지** — font-size 외 모든 수치는 동적 계산. 어떤 MDX가 들어와도 동일하게 동작
3. **스크롤 절대 금지** — overflow:auto/scroll 어떤 영역에서도 불허
4. **Kei API 필수** — fallback 없음. 성공할 때까지 무한 재시도
5. **AI가 옵션 생성, Kei가 결정** — 공간 부족 시 하드코딩 대응이 아니라 Kei 판단 요청
6. **계산 먼저, AI 판단 나중에, 렌더링은 검증만**
7. **overflow 상태에서 출력 금지** — Vision 모델 품질 게이트 통과 필수
---
## 블록 라이브러리 (38개)
6개 카테고리, 38개 블록. 각 블록은 `catalog.yaml`에 용도(when), 금지(not_for), purpose_fit, schema(슬롯 정의)가 있음.
| 카테고리 | 개수 | 용도 |
|---------|------|------|
| **headers** | 5 | 타이틀, 꼭지 헤더 |
| **cards** | 9 | 항목 나열, 카드 그리드 |
| **tables** | 3 | 비교표, 데이터 테이블 |
| **visuals** | 6 | SVG 다이어그램, 관계도 |
| **emphasis** | 10 | 강조, 인용, 결론, 불릿 |
| **media** | 5 | 이미지/사진 |
---
## 기술 스택
| 역할 | 도구 |
|------|------|
| 서버 | FastAPI + uvicorn (포트 8001) |
| AI (Kei 실장/편집자) | Kei API → Opus (localhost:8000) |
| AI (HTML 생성) | Anthropic API → Claude Sonnet |
| AI (품질 검증) | Anthropic API → Claude Opus Vision |
| 블록 검색 | FAISS + bge-m3 |
| 템플릿 | Jinja2 (블록 디자인 레퍼런스용) |
| 렌더링 | CSS Grid + 디자인 토큰 (1280×720) |
| 렌더링 측정 | Selenium headless Chrome |
| SVG 시각화 | svg_calculator.py (N개 동적 배치) |
| 이미지 | Pillow (크기 측정) + base64 인라인 |
| 폰트 | Pretendard Variable |
| 공간 계산 | space_allocator.py + fit_verifier.py (결정론적) |
---
## 설치 및 실행
```bash
# 설치
cd design_agent
pip install -e .
# FAISS 인덱스 빌드 (블록 추가/수정 시)
python scripts/build_block_index.py
# .env 설정
ANTHROPIC_API_KEY=sk-ant-...
KEI_API_URL=http://localhost:8000
LOG_LEVEL=DEBUG
```
```bash
# 터미널 1: Kei API (필수)
cd D:\ad-hoc\kei\persona_agent
python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
# 터미널 2: Design Agent
cd D:\ad-hoc\kei\design_agent
python -m uvicorn src.main:app --host 127.0.0.1 --port 8001 --reload
```
접속: http://localhost:8001
---
## 개선 이력
| Phase | 내용 | 상태 |
|-------|------|------|
| A~D | 슬라이드 품질 핵심 | 완료 |
| G~N | Kei API, 스토리라인, 정합성, 블록 선택, 비중, 측정 | 완료 |
| O | 컨테이너 기반 레이아웃 | 완료 |
| P | 다후보 렌더링 비교 | 완료 (20/100점 → 방향 전환) |
| Q | 제약 기반 블록 선택 | 완료 |
| R | 하이브리드 블록 (실패 — P=Q=R 동일 구조) | 실패 |
| R' | 블록 CSS 참고 + AI 구조 결정 | 설계 확정 |
| S | 검증 합격 프롬프트 + Claude HTML 생성 | 설계 확정 |
| T | 11-Stage 파이프라인 + 디자인 레퍼런스 | 완료 (31/31 통과) |
| V | 적합성 검증 + Kei 에스컬레이션 + 서브 컨테이너 | 완료 |
| W | Stage 2 출력 품질 수정 (6건) | 진행 중 |
---
## Kei Persona와의 관계
```
Kei Persona Agent (localhost:8000)
├── Opus + RAG + 세션 컨텍스트
├── 도메인 지식 (건설/DX/BIM)
└── 대화/생성/피드백/실행 모드
Design Agent (localhost:8001, 이 프로젝트)
├── 슬라이드 생성 전용
├── Kei API로 꼭지 추출(1A) + 컨셉 구체화(1B) + 에스컬레이션(1.8) 호출
├── Sonnet으로 HTML 생성(Stage 2)
├── Opus Vision으로 품질 검증(Stage 4)
└── 두 프로젝트는 독립. 코드 공유 없음. API 연동만.
```