from fastapi import APIRouter, BackgroundTasks, Query from pydantic import BaseModel from services.embedding_service import ( sync_all_issues, sync_single_issue, sync_incremental, search_similar_by_id, search_similar_by_text, ) from db.vector_store import vector_store router = APIRouter(tags=["embeddings"]) class SyncSingleRequest(BaseModel): issue_id: int class SearchRequest(BaseModel): query: str n_results: int = 5 project_id: int | None = None category: str | None = None @router.post("/embeddings/sync") async def sync_embeddings(background_tasks: BackgroundTasks): background_tasks.add_task(sync_all_issues) return {"status": "sync_started", "message": "전체 임베딩 동기화가 시작되었습니다"} @router.post("/embeddings/sync-full") async def sync_embeddings_full(): result = await sync_all_issues() return {"status": "completed", **result} @router.post("/embeddings/sync-single") async def sync_single(req: SyncSingleRequest): result = await sync_single_issue(req.issue_id) return result @router.post("/embeddings/sync-incremental") async def sync_incr(): result = await sync_incremental() return result @router.get("/similar/{issue_id}") async def get_similar(issue_id: int, n_results: int = Query(default=5, le=20)): try: results = await search_similar_by_id(issue_id, n_results) return {"available": True, "results": results, "query_issue_id": issue_id} except Exception as e: return {"available": False, "results": [], "error": str(e)} @router.post("/similar/search") async def search_similar(req: SearchRequest): filters = {} if req.project_id is not None: filters["project_id"] = str(req.project_id) if req.category: filters["category"] = req.category try: results = await search_similar_by_text( req.query, req.n_results, filters or None ) return {"available": True, "results": results} except Exception as e: return {"available": False, "results": [], "error": str(e)} @router.get("/embeddings/stats") async def embedding_stats(): return vector_store.stats()