Files
C.E.L_Slide_test2/ARCHITECTURE_OVERVIEW.md
kyeongmin d57860578f PIPELINE.md 신규 작성 + ARCHITECTURE_OVERVIEW.md deprecated 처리
파이프라인 현황 문서 신규 작성:
- Stage 0~4 전체 흐름, Type A/B/B'/B'' 구분, MDX↔유형 매핑
- 단계별 파일/함수 맵, 데이터 흐름, 현재 구현 상태
- ARCHITECTURE_OVERVIEW.md는 3/27 스냅샷으로 archived 처리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:51:01 +09:00

24 KiB
Raw Permalink Blame History

⚠ DEPRECATED — 이 문서는 2026-03-27 기준 스냅샷입니다

최신 파이프라인 문서는 PIPELINE.md를 참조하세요. 이 문서는 Type A/B 분기, B'/B'' 변형, Stage 1.7/1.8 등 현재 구조를 반영하지 않습니다. 히스토리 참고용으로만 유지합니다.


Design Agent 전체 구조 파악 리포트 (archived)

작성일: 2026-03-27
목표: design_agent의 아키텍처, 파이프라인, 코드 구조를 체계적으로 이해


📌 Design Agent란?

목적: 텍스트/MDX 콘텐츠를 시각적으로 구조화된 슬라이드 HTML(1280×720px, 16:9)로 변환하는 독립 AI 에이전트.

핵심 특징:

  • 콘텐츠 기반 동적 비중 — Kei가 매번 콘텐츠마다 본심/배경/첨부/결론의 비중을 판단 (고정값 없음)
  • 텍스트 우선 설계 — 디자인이 텍스트에 맞춤 (텍스트를 자르거나 비틀지 않음)
  • 전문가 판단 — Kei 실장이 꼭지 추출, 디자인 팀장이 레이아웃, 편집자가 텍스트 정리, 실무자가 디자인 조정
  • Kei API 필수 — 하드코딩 없음. 모든 판단은 AI의 사고. fallback 없음. 성공할 때까지 무한 재시도.
  • 블록 라이브러리 — 38개 블록, 6개 카테고리 (headers, cards, tables, visuals, emphasis, media)
  • 중간 산출물 추적 — 각 단계별 결과가 JSON으로 저장 (data/runs/{timestamp}/)

🏗️ 파이프라인: 5단계 + 중간 단계

┌─────────────────────────────────────────────────────────────┐
│ [입력] 텍스트 콘텐츠 (텍스트 붙여넣기 또는 파일 업로드)        │
└────────────────────┬────────────────────────────────────────┘
                     ↓
        ┌────────────────────────────┐
        │  [1단계] Kei 실장          │ (Kei API / Opus)
        │  꼭지 추출 + 정보구조 분석 │
        │  ─────────────────────────  │
        │  1A: 핵심 메시지, 꼭지 5개  │
        │  1B: 컨셉 구체화           │
        │  출력: step1_analysis.json │
        │       step1b_concepts.json │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │ [O-1] 컨테이너 계산        │ (코드 / 결정론적)
        │ 비중 → px 확정             │
        │ ─────────────────────────  │
        │ 출력: step1c_containers... │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │  [2단계] 디자인 팀장       │
        │  레이아웃 설계 + 블록 배치 │
        │ ─────────────────────────  │
        │ Step A: 프리셋 선택 (규칙) │
        │         reference 있음     │
        │         → sidebar-right    │
        │ Step B: 블록 매핑 (Sonnet) │
        │         각 블록에 텍스트   │
        │         글자수 가이드      │
        │ 출력: step2_layout.json    │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │ [O-3] 블록 스펙 확정       │ (코드 / 결정론적)
        │ 항목수, 글자수, 폰트       │
        │ ─────────────────────────  │
        │ 출력: step2c_block_specs.. │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │  [3단계] 텍스트 편집자     │ (Kei API / Opus)
        │  각 슬롯에 텍스트 정리     │
        │ ─────────────────────────  │
        │ • 팀장의 글자 수 가이드    │
        │ • 의미 우선                │
        │ • 원본 보존 + 편집         │
        │ 출력: step3_filled_blocks. │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │  [4단계] 디자인 실무자     │ (Sonnet + Jinja2)
        │  CSS 조정 + HTML 조립      │
        │ ─────────────────────────  │
        │ • 텍스트에 맞게 디자인     │
        │ • 이미지/표 처리           │
        │ • HTML 렌더링              │
        │ 출력: step4_rendered.html  │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │ [Phase L] 렌더링 측정      │ (Selenium)
        │ 실제 높이 측정             │
        │ ─────────────────────────  │
        │ • overflow 감지            │
        │ • 피드백 루프 (미완성)     │
        │ 출력: step4_measurement_.. │
        └────────┬───────────────────┘
                 ↓
        ┌────────────────────────────┐
        │  [5단계] Kei 최종 검수     │ (Opus 멀티모달)
        │  스크린샷 보고 검증        │
        │ ─────────────────────────  │
        │ 출력: step5_screenshot.txt │
        └────────┬───────────────────┘
                 ↓
┌─────────────────────────────────────────────────────────────┐
│ [출력] 완성 슬라이드 HTML (final.html)                       │
│ + 시각화 리포트 (report.html)                               │
└─────────────────────────────────────────────────────────────┘

👥 5가지 역할 (Role)

1 Kei 실장 (Opus)

역할: 전략과 콘텐츠 분석
소유 단계: 1A, 1B, 3, 5

단계 하는 일 출력
1A 꼭지 5개 추출, 핵심 메시지, 본심/배경/첨부/결론 비중 판단 step1_analysis.json
1B 각 꼭지의 relation_type, expression_hint, source_data step1b_concepts.json
3 팀장의 글자 수 가이드를 참고하며 원본 보존하며 텍스트 정리 step3_filled_blocks.json
5 최종 슬라이드의 스크린샷로 보고 최종 검수 step5_screenshot.txt

원칙:

  • 비중이 모든 것을 결정 (본심 60%, 배경 20%, 첨부 10%, 결론 10% 등)
  • 콘텐츠마다 비중은 달라짐 (고정값 없음)
  • 하드코딩 없음 - 매번 사고하여 판단

2 디자인 팀장 (Sonnet)

역할: 레이아웃과 공간 배분
소유 단계: 2 (Step B), 2 (Step A는 코드)

단계 하는 일 출력
2A 규칙 기반 프리셋 선택 (코드가 수행) 프리셋 CSS grid
2B 프리셋 내에서 블록 매핑, 글자 수 가이드 (Sonnet) step2_layout.json

원칙:

  • 블록 타입 변경 불가 (Kei가 선택한 것 유지)
  • zone 배치만 담당 (body/sidebar/footer)
  • 텍스트 내용 건드리지 않음

3 텍스트 편집자 (Opus)

역할: 콘텐츠 정리 및 편집
소유 단계: 3 (별도 호출)

원칙:

  • 팀장의 글자 수 가이드 참고 (하지만 의미가 우선)
  • 원본 텍스트 최대 보존
  • 개조식(불릿, 번호) 사용
  • 슬롯 빈칸 금지

4 디자인 실무자 (Sonnet + 코드)

역할: 디자인 조정 및 HTML 조립
소유 단계: 4 (O-3 스펙 확정 후)

원칙:

  • 텍스트를 자르지 않음. 디자인으로 텍스트 맞추기
  • 이미지는 원본 그대로, 크기만 조절
  • 표는 표로 유지 (다른 형태 전환 X)

5 Code (결정론적 알고리즘)

역할: 계산 및 측정
소유 단계: O-1 컨테이너 계산, O-3 블록 스펙, Phase L 측정

단계 하는 일
O-1 Kei 비중 → px 확정. 고정식 계산.
O-3 컨테이너 크기 → 블록별 항목수/글자수/폰트 계산. 결정론적.
Phase L Selenium으로 실제 렌더링 높이 측정. 브라우저 엔진 기반.

📂 소스 코드 구조

src/
├── main.py                 ← FastAPI 서버, /api/generate 엔드포인트
├── config.py              ← 설정 (API key, Kei API URL, 슬라이드 크기)
│
├── ─ 파이프라인 핵심 ─
├── pipeline.py            ← 메인 파이프라인 (5단계 + 중간 단계)
│   • generate_slide() — 비동기 제너레이터, SSE 이벤트 방출
│   • _retry_kei() — Kei API 무한 재시도
│
├── ─ 단계별 모듈 ─
├── kei_client.py          ← 1단계: Kei API 호출
│   • classify_content() — 꼭지 추출 + 분석 (1A)
│   • refine_concepts() — 컨셉 구체화 (1B)
│   • call_kei_overflow_judgment() — Phase L 피드백
│   • call_kei_final_review() — 최종 검수 (5)
│
├── space_allocator.py     ← O-1, O-3: 컨테이너 & 블록 스펙 계산
│   • calculate_container_specs() — 비중 → px
│   • finalize_block_specs() — 항목수/글자수/폰트
│   • calculate_trim_chars() — overflow px → 삭제 글자
│
├── design_director.py     ← 2단계: 레이아웃 설계
│   • select_preset() — 프리셋 규칙 선택 (Step A)
│   • create_layout_concept() — 블록 매핑 (Step B, Sonnet)
│   • LAYOUT_PRESETS — 4개 프리셋 (sidebar-right, two-column, hero-detail)
│   • BLOCK_SLOTS — 모든 블록의 슬롯 정의
│
├── content_editor.py      ← 3단계: 텍스트 편집
│   • fill_content() — 각 슬롯에 텍스트 정리 (Kei API)
│
├── renderer.py            ← 4단계: HTML 렌더링
│   • render_slide() — Jinja2로 HTML 생성
│   • _load_catalog_map() — catalog.yaml 블록 매핑
│
├── ─ 보조 모듈 ─
├── block_search.py        ← FAISS 기반 블록 검색
│   • search_blocks_for_topics() — 콘텐츠 적합 블록 후보
│
├── slide_measurer.py      ← Phase L: Selenium 렌더링 측정
│   • measure_rendered_heights() — 실제 높이 측정
│   • format_measurement_for_kei() — 측정값 → 피드백 포맷
│   • capture_slide_screenshot() — 멀티모달용 스크린샷
│
├── image_utils.py         ← 이미지 처리
│   • get_image_sizes() — 이미지 크기 측정
│   • embed_images() — 이미지 데이터 URI 변환
│
├── svg_calculator.py      ← SVG 다이어그램 계산
│
└── sse_utils.py           ← SSE 스트리밍 유틸
    • stream_sse_tokens() — 토큰 스트리밍 처리

📊 데이터 흐름

입력: SlideRequest

{
  "content": "텍스트/MDX 콘텐츠 (붙여넣기 또는 파일 업로드)",
  "base_path": "/path/to/images" (선택, 이미지 폴더 경로)
}

1단계 출력: step1_analysis.json

{
  "title": "슬라이드 제목",
  "core_message": "핵심 메시지 한 줄",
  "total_pages": 1,
  "info_structure": "정보 구조 설명",
  "page_structure": {
    "본심": {"topic_ids": [3], "weight": 0.60},
    "배경": {"topic_ids": [1, 2], "weight": 0.20},
    "첨부": {"topic_ids": [4], "weight": 0.10},
    "결론": {"topic_ids": [5], "weight": 0.10}
  },
  "topics": [
    {
      "id": 1,
      "title": "개념 혼용의 현실",
      "purpose": "문제제기",
      "role": "flow",
      "emphasis": false,
      "layer": "intro"
    }
  ]
}

2단계 출력: step2_layout.json

{
  "preset": "'header header' 'body sidebar' 'footer footer'",
  "blocks": [
    {
      "area": "body",
      "type": "callout-warning",
      "topic_id": 1,
      "purpose": "문제제기",
      "reason": "..."
    }
  ],
  "overflow": [
    {
      "area": "body",
      "overflow_px": 100,
      "budget_px": 490
    }
  ]
}

3단계 출력: step3_filled_blocks.json

{
  "blocks": [
    {
      "type": "callout-warning",
      "topic_id": 1,
      "data": {
        "icon": "⚠️",
        "title": "DX와 BIM의 개념적 혼용 문제",
        "description": "건설산업에서 DX와 BIM이 명확히 정립되지 않은 채 혼용..."
      },
      "char_count": 124
    }
  ]
}

최종 출력: final.html

완성된 슬라이드 HTML (1280×720px, 16:9 비율)


🎨 프리셋 시스템 (2단계 Step A)

규칙 기반 자동 선택:

프리셋 조건 CSS Grid 사용
sidebar-right reference 꼭지 1개 이상 "title title" "body sidebar" "footer" (65fr 35fr) 용어 정의, 참조 정보가 있을 때
two-column 모든 flow 꼭지가 대등한 비교 "title title" "left right" "footer" (1fr 1fr) 좌우 비교 구조
hero-detail 고강조 꼭지 1개 + 나머지 보조 "title" "hero" "detail" "footer" 하나의 큰 내용 + 상세
single-column 모든 꼭지가 flow, 순차적 "title" "body" "footer" (1fr) 일반적인 순차 흐름

🏷️ 블록 라이브러리 (38개)

카테고리 개수 용도 예시
headers 5 타이틀, 꼭지 헤더 section-title-with-bg, topic-left-right
cards 10 항목 나열, 카드 그리드 card-image-3col, card-compare-3col
tables 3 비교표, 데이터 테이블 data-table, comparison-table
visuals 6 SVG 다이어그램 venn-diagram, flow-process, relationship
emphasis 10 강조, 인용, 결론 callout-warning, quote-block, banner-gradient
media 5 이미지/사진 image-frame, full-width-image

각 블록은 catalog.yaml에 정의됨:

  • id: 블록 ID
  • template: HTML 템플릿 경로
  • height_cost: 크기 등급 (compact/medium/large/xlarge)
  • slots: 필수/선택 슬롯
  • when: 사용 조건
  • not_for: 금지 조건

🔧 기술 스택

Backend (Python)

FastAPI ≥0.115          — 웹 서버
uvicorn ≥0.30           — ASGI 서버
Jinja2 ≥3.1             — HTML 템플릿
Pydantic ≥2.0           — 데이터 검증
Anthropic ≥0.40         — Claude API
httpx ≥0.27             — HTTP 클라이언트
sse-starlette ≥2.0      — SSE 스트리밍
Selenium                — Headless Chrome 제어 (Phase L)
Pillow ≥10.0            — 이미지 처리
PyYAML ≥6.0             — YAML 파싱 (catalog.yaml)

Frontend (React + Vite)

React 18                 UI 프레임워크
Vite                     번들러
Tailwind CSS             스타일링

Design Assets

static/
├── base.css            — 슬라이드 기본 스타일
├── tokens.css          — 디자인 토큰 (색상, 폰트, 간격)
├── index.html          — 프론트엔드 UI

templates/
├── catalog.yaml        — 블록 라이브러리 정의
├── slide-base.html     — 슬라이드 기본 템플릿
└── blocks/             — 6개 카테고리 × 38개 블록 HTML
    ├── headers/        — 5개
    ├── cards/          — 10개
    ├── tables/         — 3개
    ├── visuals/        — 6개
    ├── emphasis/       — 10개
    └── media/          — 5개

🔄 Kei API 연동

무한 재시도 메커니즘

async def _retry_kei(fn, *args, **kwargs):
    """성공할 때까지 무한 재시도"""
    while True:
        result = await fn(*args, **kwargs)
        if result is not None:
            return result
        await asyncio.sleep(10)  # 10초 대기 후 재시도

특징:

  • fallback 없음 (모든 판단을 Kei가 함)
  • 타임아웃 없음 (10분이든 1시간이든 기다림)
  • 성공 또는 명시적 실패만 가능

호출 파이프라인

design_agent (Sonnet)
    ↓ HTTP POST
persona_agent (Opus)
    ↓ (구조화된 프롬프트)
Kei 페르소나 (고급 OS 모델)
    ↓ (판단)
JSON 응답 (역직렬화)
    ↓
design_agent 계속 진행

📁 폴더 구조

design_agent/
├── CLAUDE.md              ← 프로젝트 규칙 & 아키텍처 (이 파일)
├── README.md              ← 사용자 가이드
├── PLAN.md                ← 실행 계획 (태스크 목록)
├── PROGRESS.md            ← 진행 상황 추적
├── pyproject.toml         ← Python 의존성 정의
├── package.json           ← Node.js 의존성 (프론트 관련)
│
├── src/                   ← Python 소스 코드 (백엔드)
│   ├── main.py           — FastAPI 서버
│   ├── pipeline.py       — 파이프라인 메인 로직
│   ├── kei_client.py     — Kei API 호출
│   ├── design_director.py — 2단계 레이아웃
│   ├── space_allocator.py — O-1, O-3 계산
│   ├── content_editor.py — 3단계 텍스트 정리
│   ├── renderer.py       — 4단계 HTML 렌더링
│   ├── block_search.py   — FAISS 블록 검색
│   ├── slide_measurer.py — Phase L 측정
│   ├── image_utils.py    — 이미지 처리
│   ├── sse_utils.py      — SSE 스트리밍
│   └── config.py         — 설정
│
├── templates/             ← HTML 템플릿 & 블록 정의
│   ├── catalog.yaml      — 38개 블록 라이브러리
│   ├── slide-base.html   — 슬라이드 기본 구조
│   └── blocks/           — 블록별 HTML
│       ├── headers/      — 5개 헤더 블록
│       ├── cards/        — 10개 카드 블록
│       ├── tables/       — 3개 테이블 블록
│       ├── visuals/      — 6개 다이어그램 블록
│       ├── emphasis/     — 10개 강조 블록
│       └── media/        — 5개 미디어 블록
│
├── static/                ← CSS & 프론트엔드
│   ├── base.css          — 슬라이드 스타일
│   ├── tokens.css        — 디자인 토큰
│   └── index.html        — 프론트엔드 UI
│
├── data/                  ← 중간 산출물 & 인덱스
│   ├── runs/{timestamp}/  — 각 실행의 단계별 결과
│   │   ├── step1_analysis.json
│   │   ├── step1b_concepts.json
│   │   ├── step1c_containers.json
│   │   ├── step2_layout.json
│   │   ├── step2c_block_specs.json
│   │   ├── step3_filled_blocks.json
│   │   ├── step4_rendered.html
│   │   ├── step4_measurement_round*.json
│   │   ├── step5_screenshot.txt
│   │   └── final.html
│   ├── block_index.faiss — FAISS 인덱스
│   └── block_metadata.json — 메타데이터
│
├── docs/                  ← 문서
│   ├── BLOCKS.md         — 블록 라이브러리 설명
│   └── OUTPUTS.md        — 산출물 구조
│
├── scripts/               ← 유틸리티 스크립트
│   ├── build_block_index.py — FAISS 인덱스 빌드
│   └── generate_run_report.py — 실행 리포트 생성
│
└── .env                   — 환경 변수 (API key, Kei API URL)

🚀 실행 흐름 (전체)

1. 사용자 입력
   POST /api/generate
   {
     "content": "콘텐츠...",
     "base_path": "/path/to/images"
   }

2. SSE 스트리밍 시작
   event: progress
   data: "1/5 Kei 실장이 꼭지를 추출 중..."

3. 파이프라인 실행 (pipeline.py)
   ├─ [1단계] kei_client.py: classify_content()
   │   → Kei API 호출, 꼭지 5개 추출
   │
   ├─ [1B] kei_client.py: refine_concepts()
   │   → Kei API, 컨셉 구체화
   │
   ├─ [O-1] space_allocator.py: calculate_container_specs()
   │   → 결정론적 계산, 비중 → px
   │
   ├─ [2] design_director.py:
   │   ├─ select_preset() — 규칙 기반 프리셋 선택
   │   └─ create_layout_concept() — Sonnet: 블록 매핑
   │
   ├─ [O-3] space_allocator.py: finalize_block_specs()
   │   → 블록별 스펙 확정
   │
   ├─ [3] content_editor.py: fill_content()
   │   → Kei API: 텍스트 정리
   │
   ├─ [4] renderer.py: render_slide()
   │   → Jinja2: HTML 생성
   │
   ├─ [Phase L] slide_measurer.py: measure_rendered_heights()
   │   → Selenium: 실제 높이 측정
   │
   └─ [5] kei_client.py: call_kei_final_review()
       → Opus 멀티모달: 최종 검수

4. 최종 출력
   event: result
   data: {
     "html": "<html>...</html>",
     "runs_id": "1774588279782"
   }

5. 프론트엔드
   ├─ iframe에 HTML 미리보기
   ├─ 다운로드 버튼 (final.html)
   └─ 리포트 버튼 (report.html)

🔍 핵심 원칙

원칙 설명 구현
비중 우선 비중이 모든 것을 결정 Kei가 page_structure 판단 → space_allocator 계산
텍스트 기준 디자인이 텍스트에 맞춤 renderer.py에서 폰트/여백 조정
Kei API 필수 fallback 없음, 무한 재시도 pipeline.py _retry_kei()
결정론적 계산 규칙 기반 자동화 space_allocator.py, design_director.py Step A
역할 분리 각 역할이 자신의 영역만 담당 CLAUDE.md Table "역할 분리"
원본 보존 콘텐츠 의미 손상 X content_editor.py 원칙
중간 산출물 모든 단계를 추적 가능하게 _save_step() 함수

📊 Phase별 상태

Phase 내용 상태
A~D 슬라이드 품질 핵심 완료
G Kei API 통신 정상화 완료
H 스토리라인 설계 기반 전환 완료
I 정합성 복구 + 넘침 처리 완료
J 블록 선택 권한 구조 재정의 완료
K communicative role 기반 위계 완료
K-1 파이프라인 스텝별 중간 산출물 저장 완료
L Selenium 렌더링 측정 + 피드백 루프 ⚠️ 진행 중
M Kei 비중 시스템 강화 완료
N 4대 핵심 문제 해결 완료
O 컨테이너 기반 레이아웃 시스템 🔄 진행 중

🎯 결론

Design Agent는:

  • 전문가 사고 기반 (Kei 실장, 디자인 팀장, 편집자, 실무자의 역할 분리)
  • 결정론적 계산과 AI 판단의 조합
  • 모든 단계를 추적 가능하게 설계
  • 텍스트 우선, 디자인은 그에 맞춤
  • 비중 기반 동적 레이아웃
  • Kei API 필수, fallback 없음

현재 진행 상태:

  • Core 완성: 1~4단계, O-1, O-3 명확히 작동
  • 진행 중: Phase L (피드백 루프), Phase O (세부 개선)
  • 테스트 필요: BF-4, BF-5, BF-6, BF-7 (렌더링 버그)