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.on_event("startup") async def startup_preload(): """서버 시작 시 FAISS 인덱스 + 임베딩 모델 미리 로드.""" try: from src.block_search import _ensure_loaded _ensure_loaded() logger.info("FAISS 인덱스 + bge-m3 모델 미리 로드 완료") except Exception as e: logger.warning(f"FAISS 미리 로드 실패 (첫 요청 시 로드): {e}") 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 base_path: 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, base_path=req.base_path): 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")