Files
C.E.L_Slide_test2/README.md
kyeongmin ffad1ba82a Phase I 실행 완료 + 프로세스 재설계 (Stage 2.5 → Stage 5)
Phase I: 전수 정합성 복구 + 넘침 처리 패러다임 전환 (14개 항목)
- I-14: SSE 유틸 공통 추출 (src/sse_utils.py 신규, 3개 파일 중복 제거)
- I-13: dead code 3건 삭제 (_call_anthropic_direct, _extract_sse_text x2) + import anthropic 제거
- I-1: STEP_B_PROMPT purpose 가이드 미존재 블록 3개 → 실존 블록 교체
- I-2: catalog.yaml not_for 13건 미존재 블록 참조 교체/제거
- I-12: BLOCK_SLOTS 주석 개수 수정 (cards 9, visuals 6, emphasis 10)
- I-10: INDEX.md 38개 동기화 (삭제된 8개 블록 행 제거)
- I-11: README.md 38개 동기화 (_legacy 제거, 트리/개수 정리)
- I-3: PURPOSE_FALLBACK 상수 + purpose 기반 미등록 블록 교체
- I-7: compare-pill-pair 단독 사용 금지 검증
- I-4: 38개 블록 전체에 slot_desc 추가
- I-5: 편집자 프롬프트에 slot_desc 전달 로직
- I-6: 제목 유사도 70% 초과 시 자동 교정
- I-9: 넘침 판단 Kei API 호출 (KEI_OVERFLOW_PROMPT, call_kei_overflow_judgment)
- I-8: 대형 콘텐츠 정보 Kei overflow 프롬프트에 포함

프로세스 재설계:
- Stage 2.5 제거 → Stage 5에서 Sonnet 감지 + Kei 판단 통합
- _review_balance() 확장: zone 예산 + overflow_detected action 추가
- Stage 5 루프에 Kei 넘침 판단 호출 통합
- _apply_adjustments()에 kei_trim/kei_restructure action 추가
- _build_overflow_context(), _convert_kei_judgment() 헬퍼 함수 추가
- DOWNGRADE_MAP은 Kei API 실패 시 비상용으로만 잔존

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:06:21 +09:00

375 lines
18 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로 변환하는 독립 에이전트.
## 개요
텍스트/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 연동만.