c31d72a877e6bdcd694a0ddbedc43b8d9240a361
수정: - sidebar 너비 420→380px (space_allocator 실측값 반영) - 글자폭 비율 출처 명확화 (space_allocator.py 실측) - body 배경 예시 계산 추가 추가: - 원인 3가지 명시 (폰트 위계 부재, 블록 디자인 선택 부재, 비율 고정) - 근본 원칙 3가지 (폰트 먼저, body 키우기, 사전 판단) - 다단 레이아웃 판단 기준 + 전환 조건 - 비율 변경 시 구체적 px 계산 + 효과 비교표 - 블록 디자인 선택 문제 섹션 (Phase T 범위 외, 별도 검토) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kei Design Agent
콘텐츠를 시각적으로 구조화된 슬라이드 HTML(1280×720px, 16:9)로 변환하는 AI 파이프라인.
개요
텍스트/MDX 콘텐츠를 입력하면 Kei 실장(Opus)이 정보 구조와 비중을 판단하고, 그 비중대로 컨테이너를 확정하고, 블록을 선택하고, 텍스트를 편집하여 슬라이드를 생성한다.
핵심 특징:
- 콘텐츠마다 비중이 동적으로 변한다 (본심 60% / 배경 20% 등 — Kei가 매번 판단)
- 비중이 컨테이너 px를 확정 → 블록과 텍스트가 컨테이너에 맞춰진다
- Kei API 필수. fallback 없음. 성공할 때까지 무한 재시도.
파이프라인 (6단계)
텍스트 입력
↓
[1단계] Kei 실장 — 꼭지 추출 + 비중 판단 (Kei API / Opus)
↓
[1.5단계] Kei 실장 — 컨셉 구체화 (Kei API / Opus)
↓
[컨테이너 계산] 비중 → px 확정 (코드, 결정론적)
↓
[2단계] 블록 선택 (Phase Q) (코드: 결정론적 + Kei 1회)
│ relation_type → 카테고리 매핑 (코드)
│ → 컨테이너 제약 필터링 (코드)
│ → 글자수 예산 계산 (코드)
│ → Kei에게 2-3개 후보 제시 → 1개 선택 (AI)
↓
[3단계] Kei 편집자 — 텍스트 정리 (예산 포함) (Kei API / Opus)
↓
[4단계] 디자인 실무자 — CSS 조정 + HTML 조립 (Sonnet + Jinja2)
↓
[검증] Selenium 렌더링 1회 → 수학적 조정 (코드, AI 없음)
↓
[품질 게이트] 비전 모델 평가 → 미달 시 교정/차단 (Opus 멀티모달)
↓
완성 슬라이드 HTML
단계별 상세
| 단계 | 담당 | AI/코드 | 역할 |
|---|---|---|---|
| 1A | Kei 실장 | Kei API (Opus) | 핵심 메시지, 꼭지 추출, page_structure(비중), purpose 부여 |
| 1B | Kei 실장 | Kei API (Opus) | relation_type, expression_hint, source_data |
| 컨테이너 | 코드 | 결정론적 | Kei 비중 → 역할별 컨테이너 px 확정, height_cost 제약 |
| 블록 선택 | 코드 + Kei | 결정론적 + AI 1회 | relation_type → 카테고리 매핑 → 컨테이너 제약 필터 → Kei 최종 선택 (Phase Q) |
| 예산 계산 | 코드 | 결정론적 | 컨테이너 px → 글자수 예산 사전 계산 → AI 편집 시 하드 제약 (Phase Q) |
| 3 | Kei 편집자 | Kei API (Opus) | 텍스트 편집 (글자수 예산 준수, 원본 보존) |
| 4 | 디자인 실무자 | Sonnet + Jinja2 | CSS 변수 override + HTML 조립 |
| 검증 | 코드 | Selenium 1회 | 검증 렌더링 — overflow 확인 (예산으로 사전 방지됨) |
| 품질 게이트 | 비전 모델 | Opus 멀티모달 | 스크린샷 기반 시각 품질 평가 (VASCAR식) — 미달 시 출력 차단 (Phase Q) |
핵심 원칙
- 비중 → 컨테이너 → 블록 → 콘텐츠 순서. 비중이 모든 것을 결정
- Kei API 필수. fallback 없음. 기본값 없음. 성공할 때까지 무한 재시도
- 계산 먼저, AI 판단 나중에, 렌더링은 검증만 (Phase Q 핵심 원칙)
- 블록 선택은 결정론적 필터링 → Kei 최종 선택. AI에게 불가능한 선택지를 주지 않는다
- 콘텐츠가 구조를 결정, 블록 CSS는 참고만 (Phase R'). AI가 HTML 구조 직접 생성
- 글자수 예산은 하드 제약. 컨테이너 px에서 수학적으로 도출, AI 편집 전에 전달
- overflow 상태에서 출력 금지. 비전 모델 품질 게이트 통과 필수
- 블록 = 시각 패턴(구조), 크기가 아님. 같은 블록이 컨테이너에 따라 항목수/폰트/패딩 변동
- 텍스트가 기준. 디자인이 텍스트에 맞춤. CSS로 사후 자르기 금지
컨테이너 시스템 (Phase O)
Kei가 판단한 비중이 시각적 레이아웃에 정확히 반영되는 구조.
슬라이드 1280×720px
├── header: 제목 (~60px 고정)
├── body (65%): 490px
│ ├── 배경 컨테이너: 490 × 20% = 98px ← Kei 비중으로 확정
│ │ └── 문제제기 + 근거사례 (compact 블록만)
│ └── 본심 컨테이너: 490 × 60% = 294px ← Kei 비중으로 확정
│ └── 핵심전달 (large/xlarge 블록 가능)
├── sidebar (35%): 490px
│ └── 첨부 컨테이너: 490px 전체
│ └── 용어 정의 (여유 있게)
└── footer: 결론 (~60px 고정)
└── banner-gradient (핵심 메시지 한 줄)
- 컨테이너 높이(px)가 블록의 height_cost를 제약
- 컨테이너 크기에서 항목수/글자수/폰트/패딩이 자동 계산
- 편집자에게 컨테이너 제약이 전달되어 텍스트 분량이 맞춰짐
개선 이력
| Phase | 내용 | 상태 |
|---|---|---|
| A~D | 슬라이드 품질 핵심 (디자인 조정, overflow 방지, 이미지 처리) | 완료 |
| G | Kei API 통신 정상화 (SSE 스트리밍, Sonnet fallback 제거, GPU 분리) | 완료 |
| H | 스토리라인 설계 기반 전환 (core_message, purpose, source_hint) | 완료 |
| I | 전수 정합성 복구 + 넘침 처리 패러다임 전환 (14건) | 완료 |
| J | 블록 선택 권한 구조 재정의 + 최종 검토 Kei 전환 | 완료 |
| K | communicative role 기반 시각적 위계 + purpose별 분량 제약 | 완료 |
| K-1 | 파이프라인 스텝별 중간 산출물 로컬 저장 (data/runs/) |
완료 |
| L | 렌더링 측정 에이전트 (Selenium headless) + 피드백 루프 | 완료 |
| M | Kei 비중 시스템 (page_structure weight) + 원본 보존 강화 | 완료 |
| N | 4대 핵심 문제 해결 — catalog 개선, fallback 전면 제거, topic_id 버그 수정, 무한 재시도 | 완료 |
| O | 컨테이너 기반 레이아웃 시스템 — 비중→px→블록제약→콘텐츠제약 | 완료 |
| P | 블록 재구성 + 실제 렌더링 비교 선택 — 후보 3개 렌더링→Kei 스크린샷 판단 | 계획 확정 |
중간 산출물
파이프라인 실행마다 data/runs/{timestamp}/에 단계별 결과가 저장된다.
| 파일 | 단계 | 내용 |
|---|---|---|
step1_analysis.json |
1A | 꼭지 추출, page_structure(비중), core_message |
step1b_concepts.json |
1B | relation_type, expression_hint, source_data |
step1c_containers.json |
O-1 | 역할별 컨테이너 스펙 (height_px, width_px, max_height_cost) |
step2_layout.json |
2 | 블록 배치 (area, type, purpose, reason) |
step2c_block_specs.json |
O-3 | 블록별 스펙 (_max_items, _max_chars, _font_size_px) |
step3_filled_blocks.json |
3 | 텍스트 편집 결과 (data, char_count) |
step4_css_adjustment.json |
4 | CSS 변수 override |
step4_rendered.html |
4 | 렌더링된 HTML |
step4_measurement_round*.json |
Phase L | Selenium 측정 (scrollHeight, overflow) |
step5_review_round*.json |
5 | Kei 검수 결과 |
final.html |
최종 | 완성 슬라이드 |
report.html |
리포트 | 전 단계 시각화 리포트 |
리포트 생성: python scripts/generate_run_report.py
블록 라이브러리 (38개)
6개 카테고리, 38개 블록. 각 블록은 catalog.yaml에 용도(when), 금지(not_for), purpose_fit이 정의됨.
| 카테고리 | 개수 | 용도 |
|---|---|---|
| headers | 5 | 타이틀, 꼭지 헤더 |
| cards | 9 | 항목 나열, 카드 그리드 |
| tables | 3 | 비교표, 데이터 테이블 |
| visuals | 6 | SVG 다이어그램, 관계도 |
| emphasis | 10 | 강조, 인용, 결론, 불릿 |
| media | 5 | 이미지/사진 |
FAISS 블록 검색: bge-m3 1024차원 임베딩 → 꼭지별 관련 블록 후보 추출
기술 스택
| 역할 | 도구 |
|---|---|
| 서버 | FastAPI + uvicorn (포트 8001) |
| AI (Kei 실장/편집자) | Kei API → Opus (localhost:8000) |
| AI (디자인 팀장/실무자) | Anthropic API → Sonnet |
| AI (최종 검수) | Anthropic API → Opus (멀티모달) |
| 블록 검색 | FAISS + bge-m3 |
| 템플릿 | Jinja2 |
| 렌더링 | CSS Grid + 디자인 토큰 (1280×720) |
| 렌더링 측정 | Selenium headless Chrome |
| SVG 시각화 | svg_calculator.py (N개 동적 배치) |
| 이미지 | Pillow (크기 측정) + base64 인라인 |
| 폰트 | Pretendard Variable |
| 공간 계산 | space_allocator.py (결정론적) |
설치 및 실행
# 설치
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
# 터미널 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
프로젝트 구조
design_agent/
├── src/
│ ├── main.py FastAPI 서버 (포트 8001)
│ ├── config.py 설정 (pydantic-settings)
│ ├── pipeline.py 파이프라인 오케스트레이션 (6단계)
│ ├── kei_client.py Kei API 클라이언트 (1A, 1B, 검수, 넘침 판단)
│ ├── design_director.py 2단계: 프리셋 + Kei 블록 확정 + Sonnet zone 배치
│ ├── content_editor.py 3단계: Kei API 텍스트 편집
│ ├── renderer.py 4단계: HTML 조립 (컨테이너 grid + Jinja2)
│ ├── space_allocator.py 컨테이너 스펙 계산 + 블록 스펙 확정 (Phase O)
│ ├── slide_measurer.py Selenium 렌더링 측정 + 스크린샷 (Phase L/N)
│ ├── block_search.py FAISS 블록 검색
│ ├── svg_calculator.py SVG 좌표 계산 (N개 동적 배치)
│ ├── image_utils.py 이미지 크기 측정 + base64 삽입
│ └── sse_utils.py SSE 스트리밍 유틸
│
├── templates/
│ ├── slide-base.html 슬라이드 베이스
│ ├── catalog.yaml 블록 카탈로그 (38개, when/not_for/purpose_fit)
│ └── blocks/ 블록 라이브러리 (6 카테고리)
│
├── scripts/
│ ├── build_block_index.py FAISS 인덱스 빌드
│ └── generate_run_report.py 실행 리포트 생성
│
├── static/ 프론트엔드 (index.html, CSS)
├── data/ 로컬 데이터 (runs/, FAISS 인덱스)
├── docs/ 기술 조사, Figma 분석
│
├── IMPROVEMENT.md 개선 계획 총괄 (Phase A~O)
├── IMPROVEMENT-PHASE-*.md 각 Phase 상세
└── PROGRESS.md 진행 상황 추적
Kei Persona와의 관계
Kei Persona Agent (localhost:8000)
├── Opus + RAG + 세션 컨텍스트
├── 도메인 지식 (건설/DX/BIM)
└── 대화/생성/피드백/실행 모드
Design Agent (localhost:8001, 이 프로젝트)
├── 슬라이드 생성 전용
├── Kei API로 실장(1단계) + 편집자(3단계) + 블록 확정(2단계) 호출
├── 최종 검수(5단계)는 Opus 직접 호출 (멀티모달 스크린샷)
└── 두 프로젝트는 독립. 코드 공유 없음. API 연동만.
Description
Languages
Python
86.6%
HTML
12.7%
CSS
0.7%