# Kei Design Agent 콘텐츠를 시각적으로 구조화된 슬라이드 HTML로 변환하는 독립 에이전트. ## 개요 텍스트/MDX 콘텐츠를 입력하면, AI가 정보 구조를 파악하고 적합한 레이아웃과 블록을 선택하여 깔끔한 1페이지(또는 다중 페이지) 슬라이드를 생성합니다. ## 아키텍처 (5단계 파이프라인) ``` 텍스트 입력 (+ 이미지 폴더 경로) ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [1단계] Kei 실장 — 콘텐츠 분석 + 스토리라인 설계 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ 사용 AI: Kei API (Opus) │ fallback: manual_classify() (최소 구조 생성) │ │ 1-A: 정보 구조 파악 + 꼭지 추출 │ - 핵심 메시지(core_message) 도출 │ - 본문 흐름(flow) vs 참조 정보(reference) 분리 │ - 각 꼭지의 레이어/강조/배치 방향 판단 │ - 이미지 판단 (개수/소속/핵심·보조/텍스트 포함 여부) │ - 표 판단 (행/열 규모, 1페이지 표시 가능 여부) │ - purpose 부여 (문제제기/근거사례/핵심전달/용어정의/결론강조/구조시각화) │ │ 1-B: 각 꼭지 컨셉 구체화 │ - relation_type (비교/포함/계층/인과 등) │ - expression_hint (표현 방향) │ - source_data (원본에서 추출할 데이터) │ │ 제목 중복 검증 (I-6) │ - 슬라이드 제목 ↔ 첫 꼭지 제목 유사도 70% 초과 시 자동 교정 │ │ 이미지 크기 측정 (Pillow) │ - base_path 있으면 이미지 파일 크기 측정 → analysis에 포함 │ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [2단계] 디자인 팀장 — 레이아웃 설계 + 블록 매핑 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ Step A-1: 레이아웃 프리셋 자동 선택 (규칙 기반, LLM 불필요) │ - sidebar-right / two-column / hero-detail / single-column │ - grid는 코드가 프리셋에서 강제 (AI가 변경 불가) │ │ Step A-2: Opus(Kei API) 블록 추천 (FAISS 검색 결과 기반) │ 사용 AI: Kei API (Opus) │ - 도메인 지식 + 콘텐츠 성격 기반 블록 추천 │ - fallback: 추천 없이 Step B로 │ │ Step B: 블록 매핑 + 글자 수 가이드 (Sonnet) │ 사용 AI: Anthropic API (Sonnet) │ - Opus 추천 참고하되 최종 선택은 팀장 판단 │ - 컨테이너 예산(zone별 높이 px) 기반 블록 선택 │ - purpose 기반 블록 선택 가이드 참고 │ - 각 블록에 char_guide(글자 수 가이드) 부여 │ │ 블록 검증 (코드): │ - 미등록 블록 → purpose 기반 fallback (PURPOSE_FALLBACK) │ - 잘못된 zone → 기본 zone 자동 매핑 │ - conclusion 꼭지 → footer zone 강제 │ - compare-pill-pair 단독 사용 → comparison-2col 교체 (I-7) │ - 금지 블록(section-title-with-bg) → body/sidebar에서 교체 │ │ 높이 예산 검증 (I-9): │ - zone별 블록 높이 합산 vs budget_px 비교 │ - 초과 시 → overflow 정보 수집 (블록 자동 교체 안 함) │ ↓ (overflow 있으면) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [2.5단계] Kei 실장 — 넘침 판단 (I-9) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ 사용 AI: Kei API (Opus) │ 조건: 2단계에서 overflow 발생 시에만 실행 │ │ Kei에게 전달: 어떤 zone이 얼마나 초과, 블록/콘텐츠 요약, 대형 테이블/이미지 정보 (I-8) │ │ Kei가 판단: │ Option 1 "trim" → 텍스트 분량 제약 (char_guide 축소) → 3단계에서 반영 │ Option 2 "restructure" → 핵심 재구성 + 상세는 팝업(detail page) 분리 │ → detail_target 설정 후 2단계 재실행 │ │ Kei API 실패 시: DOWNGRADE_MAP 비상 작동 (기계적 블록 교체) │ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [3단계] Kei 텍스트 편집자 — 도메인 전문가로서 텍스트 정리 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ 사용 AI: Kei API (Opus + RAG + 도메인 지식) │ Sonnet fallback 없음 (Kei API만 사용) │ │ - 각 블록의 슬롯에 맞게 텍스트 정리 │ - 슬롯 의미 설명(slot_desc) 참고하여 정확한 데이터 배치 (I-4, I-5) │ - 글자 수 가이드 참고, 내용 의미 우선 │ - 2.5단계에서 trim 제약이 있으면 반영 │ - 원본 텍스트 최대 보존, 출처 보존, 개조식, 날조 금지 │ - detail_target 꼭지: summary + detail 두 버전 작성 │ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [4단계] 디자인 실무자 — 디자인 조정 + HTML 조립 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ 사용 AI: Anthropic API (Sonnet) — CSS 변수 override 결정 │ 렌더링: Jinja2 + CSS Grid │ │ - Sonnet이 텍스트 양에 맞게 CSS 변수 override 결정 │ (--font-body, --font-subtitle, --spacing-inner, --spacing-block 등) │ - Jinja2로 블록 템플릿 렌더링 │ - CSS 변수 cascade로 area별 자동 적용 │ - SVG 시각화 블록: 좌표 사전 계산 (svg_calculator.py) │ - 이미지 base64 인라인 삽입 (다운로드 HTML에서도 표시) │ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [5단계] 디자인 팀장 — 전체 재검토 (최대 2회 루프) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ 사용 AI: Anthropic API (Sonnet) — HTML 기반 균형 점검 │ │ 점검 항목: │ - 빈 블록 감지 │ - 채움 불균형 (한 블록은 빽빽, 다른 블록은 비어있음) │ - 이미지/표 크기 적절성 │ - 전체 정보량 (페이지당 너무 많거나 적은지) │ │ 조정 필요 시: │ - expand: 텍스트 늘림 (target_ratio, 예: 1.3 = 30% 증가) │ - shrink: 텍스트 줄임 (target_ratio, 예: 0.7 = 30% 감소) │ - rewrite: 텍스트 재작성 (방향 명시) │ → 3단계(Kei 편집자) 재호출 → 4단계 재렌더링 → 재검토 │ │ 조정 불필요 또는 2회 완료 시 확정 │ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 미리보기 + HTML 다운로드 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` ### 각 단계별 AI 담당 | 단계 | 담당 | AI | session_id | |------|------|-----|-----------| | 1-A | Kei 실장 | Kei API (Opus) | `design-agent` | | 1-B | Kei 실장 | Kei API (Opus) | `design-agent-refine` | | 2 A-2 | Kei 실장 | Kei API (Opus) | `design-agent-opus` | | 2 B | 디자인 팀장 | Anthropic (Sonnet) | — | | 2.5 | Kei 실장 | Kei API (Opus) | `design-agent-overflow` | | 3 | Kei 편집자 | Kei API (Opus) | `design-agent-editor` | | 4 | 디자인 실무자 | Anthropic (Sonnet) | — | | 5 | 디자인 팀장 | Anthropic (Sonnet) | — | ## 블록 라이브러리 (38개) ``` templates/blocks/ ├── INDEX.md 전체 인덱스 ├── headers/ (5개) 타이틀, 꼭지 헤더 │ ├── section-title-with-bg.html 배경 이미지 + 영문/한글 │ ├── section-header-bar.html 파란 배경 바 + 제목 │ ├── topic-left-right.html 좌:제목 + 우:설명 │ ├── topic-center.html 중앙 정렬 제목 │ └── topic-numbered.html 번호 + 제목 + 설명 ├── cards/ (9개) 카드 계열 │ ├── card-image-3col.html 이미지 카드 3열 │ ├── card-dark-overlay.html 다크 오버레이 카드 │ ├── card-tag-image.html 태그 + 이미지 카드 │ ├── card-icon-desc.html 아이콘 + 설명 카드 │ ├── card-compare-3col.html 비교 카드 3열 │ ├── card-step-vertical.html 세로 단계 카드 │ ├── card-image-round.html 원형 이미지 카드 │ ├── card-stat-number.html 큰 숫자 KPI 카드 │ └── card-numbered.html 번호 리스트 카드 ├── tables/ (3개) 비교 테이블 │ ├── compare-3col-badge.html A|VS배지|B 3단 비교 │ ├── compare-2col-split.html 좌우 분할 비교 │ └── table-simple-striped.html 줄무늬 일반 테이블 ├── visuals/ (6개) 다이어그램, 관계도 (SVG) │ ├── venn-diagram.html 벤 다이어그램 (N개 동적) │ ├── circle-gradient.html 그라데이션 원 + 텍스트 │ ├── compare-pill-pair.html 둥근 박스 2개 + VS │ ├── process-horizontal.html 가로 단계 흐름 │ ├── flow-arrow-horizontal.html 가로 화살표 흐름 │ └── keyword-circle-row.html 키워드 원형 나열 ├── emphasis/ (10개) 강조, 인용, 결론 │ ├── quote-big-mark.html 큰 따옴표 인용 │ ├── quote-question.html 질문형 강조 │ ├── comparison-2col.html 2단 비교 │ ├── banner-gradient.html 그라데이션 배너 │ ├── dark-bullet-list.html 다크 배경 불릿 리스트 │ ├── highlight-strip.html 하이라이트 스트립 │ ├── callout-solution.html 솔루션 콜아웃 │ ├── callout-warning.html 경고 콜아웃 │ ├── tab-label-row.html 탭 라벨 행 │ └── divider-text.html 텍스트 구분선 └── media/ (5개) 이미지/미디어 ├── image-row-2col.html 이미지 2장 나란히 ├── image-grid-2x2.html 이미지 2x2 그리드 ├── image-side-text.html 이미지 + 텍스트 ├── image-full-caption.html 전체 너비 이미지 + 캡션 └── image-before-after.html Before/After 비교 ``` ## FAISS 블록 검색 38개 블록 전체를 프롬프트에 넣는 대신, FAISS로 꼭지별 관련 블록만 검색하여 전달합니다. ``` 꼭지 "A vs B 비교" → FAISS 검색 → comparison-2col, compare-pill-pair, compare-2col-split 꼭지 "연도별 로드맵" → FAISS 검색 → process-horizontal, flow-arrow-horizontal, card-step-vertical ``` - 임베딩 모델: BAAI/bge-m3 (1024차원, 한국어 최적화) - 인덱스 빌드: `python scripts/build_block_index.py` - fallback: 인덱스 없으면 catalog.yaml 전문 전달 (기존 방식) ## 레이아웃 프리셋 | 프리셋 | 조건 | CSS Grid | zone 예산 | |--------|------|----------|----------| | `sidebar-right` | reference 꼭지 있음 | 65:35 좌우 분할 | body 490px, sidebar 490px | | `two-column` | 대등한 비교 | 50:50 균등 | left 490px, right 490px | | `hero-detail` | 고강조 1개 + 보조 | hero 영역 + detail | hero 310px, detail 155px | | `single-column` | 순차적 flow만 | 1열 | body 490px | grid는 코드(Step A)가 결정. Sonnet은 blocks만 출력. grid 변경 불가. ## 기술 스택 | 역할 | 도구 | |------|------| | 서버 | FastAPI + uvicorn (포트 8001) | | AI (1단계 실장) | Kei API (Opus) → fallback: Sonnet | | AI (2단계 A-2) | Kei API (Opus) — 블록 추천 | | AI (2단계 B) | Anthropic API (Sonnet) — 블록 매핑 | | AI (3단계 편집자) | Kei API → fallback: Sonnet | | AI (4단계 실무자) | Anthropic API (Sonnet) — CSS 조정 | | AI (5단계 재검토) | Anthropic API (Sonnet) — 균형 점검 | | 블록 검색 | FAISS + bge-m3 (38개 블록 인덱스) | | 템플릿 | Jinja2 (카테고리별 블록 조합) | | 렌더링 | CSS Grid + 디자인 토큰 (16:9, 1280×720) | | SVG 시각화 | svg_calculator.py (cos/sin 좌표 계산, N개 동적) | | 이미지 처리 | Pillow (크기 측정) + base64 인라인 | | 폰트 | Pretendard Variable (한국어) | ## 설치 및 실행 ### 설치 ```bash cd design_agent python -m venv .venv .venv/Scripts/activate # Windows pip install -e . ``` ### FAISS 인덱스 빌드 ```bash python scripts/build_block_index.py ``` ### 환경 변수 `.env` 파일: ```env ANTHROPIC_API_KEY=sk-ant-... KEI_API_URL=http://localhost:8000 LOG_LEVEL=DEBUG ``` ### 실행 ```bash # 터미널 1: Kei 백엔드 (Opus 실장 + 편집자 역할) cd D:\ad-hoc\kei\persona_agent uvicorn backend.main:app --reload --host 127.0.0.1 --port 8000 # 터미널 2: Design Agent cd D:\ad-hoc\kei\design_agent uvicorn src.main:app --reload --host 127.0.0.1 --port 8001 ``` 접속: http://localhost:8001 ## 프로젝트 구조 ``` design_agent/ ├── CLAUDE.md 프로젝트 규칙 + 5단계 프로세스 ├── PLAN.md 태스크 계획 ├── PROGRESS.md 진행 상황 ├── IMPROVEMENT.md 개선 계획 (Phase A~F) ├── IMPROVEMENT-PHASE-{A~D}.md 각 Phase 실행 상세 ├── README.md 이 파일 ├── pyproject.toml ├── .env API 키 │ ├── src/ 파이프라인 코드 │ ├── main.py FastAPI 서버 (포트 8001) │ ├── config.py 설정 (pydantic-settings) │ ├── kei_client.py 1단계: Kei API → 꼭지 추출 │ ├── design_director.py 2단계: 프리셋 선택 + Opus 추천 + 블록 매핑 │ ├── content_editor.py 3단계: Kei API → 텍스트 정리 │ ├── pipeline.py 5단계 파이프라인 (디자인 조정 + 재검토 루프) │ ├── renderer.py 4단계: HTML 조립 (SVG 전처리 + CSS 변수 override) │ ├── block_search.py FAISS 블록 검색 모듈 │ ├── svg_calculator.py SVG 좌표 계산 (cos/sin N개 배치) │ └── image_utils.py 이미지 크기 측정 + base64 삽입 │ ├── scripts/ │ └── build_block_index.py FAISS 인덱스 빌드 스크립트 │ ├── templates/ │ ├── slide-base.html 슬라이드 베이스 (다중 페이지 + 인쇄 JS) │ ├── catalog.yaml 블록 카탈로그 (38개, height_cost 포함) │ └── blocks/ 블록 라이브러리 (6 카테고리, 38개) │ ├── INDEX.md 전체 인덱스 │ ├── headers/ (5) 타이틀, 꼭지 헤더 │ ├── cards/ (10) 카드 계열 │ ├── tables/ (3) 비교 테이블 │ ├── visuals/ (10) 다이어그램, 관계도 (SVG) │ ├── emphasis/ (13) 강조, 인용, 결론, 자세히보기 │ ├── media/ (5) 이미지/미디어 │ └── media/ (5) 이미지/미디어 │ ├── static/ │ ├── index.html 프론트엔드 (이미지 경로 입력 팝업 포함) │ ├── tokens.css 디자인 토큰 │ └── base.css 기본 슬라이드 스타일 │ ├── data/ 로컬 데이터 (gitignored) │ ├── block_index.faiss FAISS 벡터 인덱스 │ └── block_metadata.json 인덱스 메타데이터 │ ├── docs/ │ ├── RESEARCH.md 기술 조사 │ ├── PHASE2-PLAN.md Phase 2 계획 │ ├── PHASE2-PROCESS.md Phase 2 실행 프로세스 │ ├── PHASE2-TECH-REVIEW.md Phase 2 기술 검토 │ ├── figma-screenshots/ Figma 스크린샷 (16장) │ ├── figma-assets/ Figma 에셋 │ ├── figma-analysis/ 노드 구조 분석 │ └── block-tests/ 블록 테스트 HTML │ └── tests/ ``` ## 핵심 원칙 - **모든 판단은 AI 사고. 하드코딩 없음** - 텍스트가 기준. 디자인이 텍스트에 맞춤 (텍스트를 자르지 않음) - 이미지 원본 그대로, 크기만 조절 (object-fit: contain) - 컨테이너 예산(zone별 높이 px) 안에서 블록 배치 - grid는 코드가 결정. Sonnet은 blocks만 판단 - Kei API 1차 → Sonnet fallback (1단계, 3단계) - Kei Persona Agent 코드를 수정하지 않음 ## Kei Persona와의 관계 ``` Kei Persona (본체) — localhost:5173/8000 ├ 대화/생성/피드백/실행 모드 ├ Opus + RAG (bge-m3 + FAISS) └ 독립적으로 동작 Design Agent (이 프로젝트) — localhost:8001 ├ 슬라이드 생성 전용 ├ Kei API로 실장(1단계) + 편집자(3단계) + 블록 추천(2단계 A-2) 호출 ├ FAISS 블록 검색 (bge-m3, Kei와 동일 모델) └ 독립적으로 동작 (Kei 없이도 Sonnet fallback) ``` 두 프로젝트는 완전히 독립. 코드 공유 없음. API 연동만.