Initial commit: Kei Design Agent

콘텐츠를 시각적으로 구조화된 슬라이드 HTML로 변환하는 독립 에이전트.

아키텍처 (4단계 파이프라인):
  1. Kei 실장 (Opus) — 콘텐츠 유형 분류 + 블록 배치
  2. 디자인 팀장 (Sonnet) — 레이아웃 컨셉 (블록 배치 + 페이지 수)
  3. 텍스트 편집자 (Sonnet) — 슬롯 텍스트 정리 (핵심 유지)
  4. CSS Grid 렌더러 — HTML 조립

블록 템플릿 7종:
  comparison, card-grid, relationship, process,
  quote-block, conclusion-bar, comparison-table

기술 스택:
  FastAPI + Anthropic API + Jinja2 + CSS Grid
  Pretendard Variable 한국어 폰트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 17:25:47 +09:00
commit c42e65fc7e
28 changed files with 3302 additions and 0 deletions

60
src/main.py Normal file
View File

@@ -0,0 +1,60 @@
from __future__ import annotations
import json
import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from pathlib import Path
from pydantic import BaseModel
from sse_starlette.sse import EventSourceResponse
from src.config import settings
from src.pipeline import generate_slide
logging.basicConfig(level=getattr(logging, settings.log_level, logging.DEBUG))
logger = logging.getLogger(__name__)
app = FastAPI(title="Design Agent", version="0.1.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5174", "http://localhost:5173"],
allow_methods=["*"],
allow_headers=["*"],
)
# 정적 파일 서빙 (CSS, 폰트 등)
static_dir = Path(__file__).parent.parent / "static"
if static_dir.exists():
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
class SlideRequest(BaseModel):
content: str
@app.get("/api/health")
async def health():
return {"status": "ok", "service": "design-agent"}
@app.post("/api/generate")
async def generate(req: SlideRequest):
"""콘텐츠 → 슬라이드 생성 (SSE 스트리밍)."""
async def event_stream():
async for event in generate_slide(req.content):
yield {
"event": event["event"],
"data": json.dumps(event["data"], ensure_ascii=False),
}
return EventSourceResponse(event_stream())
@app.get("/")
async def frontend():
"""프론트엔드 UI — static/index.html 서빙."""
return FileResponse(str(static_dir / "index.html"), media_type="text/html")