|
| 1 | +from fastapi import APIRouter, HTTPException, status |
| 2 | +from uuid import UUID |
| 3 | +from app.model.AgentModel import ( |
| 4 | + PlanningRequest, |
| 5 | + AgentCreateResponse, |
| 6 | + AgentGetResponse, |
| 7 | + FlowResponse, |
| 8 | + DocResponse, |
| 9 | + CompleteResponse, |
| 10 | + FlowFeedbackRequest, |
| 11 | + DocFeedbackRequest |
| 12 | +) |
| 13 | +from app.service.AgentService import AgentService |
| 14 | +import logging |
| 15 | + |
| 16 | +logger = logging.getLogger(__name__) |
| 17 | + |
| 18 | +router = APIRouter( |
| 19 | + prefix="/api/v1/agents", |
| 20 | + tags=["Agent"], |
| 21 | + responses={404: {"description": "Not found"}} |
| 22 | +) |
| 23 | + |
| 24 | +agent_service = AgentService() |
| 25 | + |
| 26 | + |
| 27 | +@router.post("", response_model=AgentCreateResponse, status_code=status.HTTP_201_CREATED) |
| 28 | +async def create_agent(planning_request: PlanningRequest): |
| 29 | + """ |
| 30 | + 1단계: Agent 생성 (Planning 단계) |
| 31 | +
|
| 32 | + 사용자로부터 학습 주제, 목적, 키워드, 참고 링크를 받아 Agent를 생성합니다. |
| 33 | + """ |
| 34 | + try: |
| 35 | + agent_data = await agent_service.create_agent(planning_request) |
| 36 | + return AgentCreateResponse( |
| 37 | + success=True, |
| 38 | + message="Agent created successfully", |
| 39 | + data=agent_data |
| 40 | + ) |
| 41 | + except Exception as e: |
| 42 | + logger.error(f"Error creating agent: {e}") |
| 43 | + raise HTTPException( |
| 44 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 45 | + detail=str(e) |
| 46 | + ) |
| 47 | + |
| 48 | + |
| 49 | +@router.get("/{agent_id}", response_model=AgentGetResponse) |
| 50 | +async def get_agent(agent_id: UUID): |
| 51 | + """ |
| 52 | + Agent 전체 상태 조회 |
| 53 | + 작업 중단 후 다시 이어하기 위해 Agent의 현재까지 모든 데이터를 조회합니다. |
| 54 | + """ |
| 55 | + try: |
| 56 | + agent = await agent_service.get_agent(agent_id) |
| 57 | + if not agent: |
| 58 | + raise HTTPException( |
| 59 | + status_code=status.HTTP_404_NOT_FOUND, |
| 60 | + detail=f"Agent with id {agent_id} not found" |
| 61 | + ) |
| 62 | + |
| 63 | + return AgentGetResponse( |
| 64 | + success=True, |
| 65 | + message="Agent retrieved successfully", |
| 66 | + data=agent |
| 67 | + ) |
| 68 | + except HTTPException: |
| 69 | + raise |
| 70 | + except Exception as e: |
| 71 | + logger.error(f"Error retrieving agent: {e}") |
| 72 | + raise HTTPException( |
| 73 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 74 | + detail=str(e) |
| 75 | + ) |
| 76 | + |
| 77 | + |
| 78 | +@router.post("/{agent_id}/flow", response_model=FlowResponse, status_code=status.HTTP_201_CREATED) |
| 79 | +async def create_flow(agent_id: UUID): |
| 80 | + """ |
| 81 | + 2단계: Flow 생성 (목차 생성) |
| 82 | +
|
| 83 | + Agent의 planning 데이터를 기반으로 학습 목차를 생성합니다. |
| 84 | + """ |
| 85 | + try: |
| 86 | + flow = await agent_service.create_flow(agent_id) |
| 87 | + if not flow: |
| 88 | + raise HTTPException( |
| 89 | + status_code=status.HTTP_404_NOT_FOUND, |
| 90 | + detail=f"Agent with id {agent_id} not found or planning not completed" |
| 91 | + ) |
| 92 | + |
| 93 | + return FlowResponse( |
| 94 | + success=True, |
| 95 | + message="Flow successfully generated", |
| 96 | + data=flow |
| 97 | + ) |
| 98 | + except HTTPException: |
| 99 | + raise |
| 100 | + except Exception as e: |
| 101 | + logger.error(f"Error creating flow: {e}") |
| 102 | + raise HTTPException( |
| 103 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 104 | + detail=str(e) |
| 105 | + ) |
| 106 | + |
| 107 | + |
| 108 | +@router.patch("/{agent_id}/flow", response_model=FlowResponse) |
| 109 | +async def update_flow(agent_id: UUID, feedback: FlowFeedbackRequest): |
| 110 | + """ |
| 111 | + 3단계: Flow 피드백 |
| 112 | +
|
| 113 | + AI가 생성한 목차를 사용자가 수정하여 업데이트합니다. |
| 114 | + """ |
| 115 | + try: |
| 116 | + flow = await agent_service.update_flow(agent_id, feedback) |
| 117 | + if not flow: |
| 118 | + raise HTTPException( |
| 119 | + status_code=status.HTTP_404_NOT_FOUND, |
| 120 | + detail=f"Agent with id {agent_id} not found" |
| 121 | + ) |
| 122 | + |
| 123 | + return FlowResponse( |
| 124 | + success=True, |
| 125 | + message="Flow feedback applied", |
| 126 | + data=flow |
| 127 | + ) |
| 128 | + except HTTPException: |
| 129 | + raise |
| 130 | + except Exception as e: |
| 131 | + logger.error(f"Error updating flow: {e}") |
| 132 | + raise HTTPException( |
| 133 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 134 | + detail=str(e) |
| 135 | + ) |
| 136 | + |
| 137 | + |
| 138 | +@router.post("/{agent_id}/doc", response_model=DocResponse, status_code=status.HTTP_201_CREATED) |
| 139 | +async def create_doc(agent_id: UUID): |
| 140 | + """ |
| 141 | + 4단계: Doc 생성 (본문 생성) |
| 142 | +
|
| 143 | + Agent의 flow 데이터를 기반으로 각 목차에 대한 상세 본문을 생성합니다. |
| 144 | + """ |
| 145 | + try: |
| 146 | + doc = await agent_service.create_doc(agent_id) |
| 147 | + if not doc: |
| 148 | + raise HTTPException( |
| 149 | + status_code=status.HTTP_404_NOT_FOUND, |
| 150 | + detail=f"Agent with id {agent_id} not found or flow not generated" |
| 151 | + ) |
| 152 | + |
| 153 | + return DocResponse( |
| 154 | + success=True, |
| 155 | + message="Documentation created successfully", |
| 156 | + data=doc |
| 157 | + ) |
| 158 | + except HTTPException: |
| 159 | + raise |
| 160 | + except Exception as e: |
| 161 | + logger.error(f"Error creating documentation: {e}") |
| 162 | + raise HTTPException( |
| 163 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 164 | + detail=str(e) |
| 165 | + ) |
| 166 | + |
| 167 | + |
| 168 | +@router.patch("/{agent_id}/doc", response_model=DocResponse) |
| 169 | +async def update_doc(agent_id: UUID, feedback: DocFeedbackRequest): |
| 170 | + """ |
| 171 | + 5단계: Doc 피드백 |
| 172 | +
|
| 173 | + AI가 생성한 본문을 사용자가 수정하여 업데이트합니다. |
| 174 | + |
| 175 | + Request Body: |
| 176 | + { |
| 177 | + "docs": [ |
| 178 | + {"index": "목차 제목", "content": "수정된 내용..."}, |
| 179 | + ... |
| 180 | + ] |
| 181 | + } |
| 182 | + """ |
| 183 | + try: |
| 184 | + doc = await agent_service.update_doc(agent_id, feedback) |
| 185 | + if not doc: |
| 186 | + raise HTTPException( |
| 187 | + status_code=status.HTTP_404_NOT_FOUND, |
| 188 | + detail=f"Agent with id {agent_id} not found" |
| 189 | + ) |
| 190 | + |
| 191 | + return DocResponse( |
| 192 | + success=True, |
| 193 | + message="Documentation feedback applied", |
| 194 | + data=doc |
| 195 | + ) |
| 196 | + except HTTPException: |
| 197 | + raise |
| 198 | + except Exception as e: |
| 199 | + logger.error(f"Error updating documentation: {e}") |
| 200 | + raise HTTPException( |
| 201 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 202 | + detail=str(e) |
| 203 | + ) |
| 204 | + |
| 205 | + |
| 206 | +@router.post("/{agent_id}/complete", response_model=CompleteResponse) |
| 207 | +async def complete_agent(agent_id: UUID): |
| 208 | + """ |
| 209 | + 6단계: 제작 완료 |
| 210 | +
|
| 211 | + 모든 단계를 종합하여 최종 마크다운 학습 자료를 생성합니다. |
| 212 | + """ |
| 213 | + try: |
| 214 | + complete_data = await agent_service.complete(agent_id) |
| 215 | + if not complete_data: |
| 216 | + raise HTTPException( |
| 217 | + status_code=status.HTTP_404_NOT_FOUND, |
| 218 | + detail=f"Agent with id {agent_id} not found or required data missing" |
| 219 | + ) |
| 220 | + |
| 221 | + return CompleteResponse( |
| 222 | + success=True, |
| 223 | + message="Lesson markdown generated successfully", |
| 224 | + data=complete_data |
| 225 | + ) |
| 226 | + except HTTPException: |
| 227 | + raise |
| 228 | + except Exception as e: |
| 229 | + logger.error(f"Error completing agent: {e}") |
| 230 | + raise HTTPException( |
| 231 | + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 232 | + detail=str(e) |
| 233 | + ) |
0 commit comments