|
| 1 | +from typing import List, Optional |
| 2 | +from fastapi import APIRouter, HTTPException |
| 3 | +from pydantic import BaseModel, Field, field_validator |
| 4 | + |
| 5 | +from app.services.gemini_category import classify_paragraph_gemini |
| 6 | + |
| 7 | +router = APIRouter() |
| 8 | + |
| 9 | +class GeminiRequest(BaseModel): |
| 10 | + paragraph: str = Field(..., description="분류 대상 문단") |
| 11 | + userCategories: Optional[List[str]] = Field(default=None, description="카테고리 후보(선택)") |
| 12 | + threshold: float = Field(default=0.5, ge=0.0, le=1.0, description="카테고리 매칭 임계값(0~1)") |
| 13 | + k: int = Field(default=5, ge=1, le=10, description="추천 개수") |
| 14 | + |
| 15 | + @field_validator("userCategories") |
| 16 | + @classmethod |
| 17 | + def _strip_empty(cls, v): |
| 18 | + if v: |
| 19 | + v = [s.strip() for s in v if isinstance(s, str) and s.strip()] |
| 20 | + if not v: |
| 21 | + return None |
| 22 | + return v |
| 23 | + |
| 24 | +class SentenceOut(BaseModel): |
| 25 | + text: str |
| 26 | + urls: Optional[List[str]] = None |
| 27 | + invalid_urls: Optional[List[str]] = None |
| 28 | + schedules: Optional[List[dict]] = None |
| 29 | + |
| 30 | +class GeminiResponse(BaseModel): |
| 31 | + category: str |
| 32 | + recommend_category: List[str] |
| 33 | + sentences: List[SentenceOut] |
| 34 | + |
| 35 | +@router.post("/gemini", response_model=GeminiResponse) |
| 36 | +async def gemini_endpoint(req: GeminiRequest): |
| 37 | + try: |
| 38 | + return await classify_paragraph_gemini( |
| 39 | + paragraph=req.paragraph, |
| 40 | + user_categories=req.userCategories, |
| 41 | + threshold=req.threshold, |
| 42 | + k=req.k |
| 43 | + ) |
| 44 | + except Exception as e: |
| 45 | + raise HTTPException(status_code=502, detail=f"Gemini 호출 실패: {e}") |
0 commit comments