Skip to content

Commit 1ade945

Browse files
authored
Merge pull request #9 from EscapeFrame/feat/#8
feat(#8) : agent 기본 기능 구현
2 parents 6bdf4ae + f2a4b4a commit 1ade945

9 files changed

Lines changed: 813 additions & 12 deletions

File tree

‎.env.example‎

Lines changed: 0 additions & 9 deletions
This file was deleted.

‎.gitignore‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,7 @@ cython_debug/
122122
# VS Code
123123
.vscode/
124124

125-
DEPLOYMENT.md
125+
# Project specific
126+
DEPLOYMENT.md
127+
WORK_LOG.md
128+
API_SPECIFICATION.md

‎app/controller/AgentController.py‎

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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+
)

‎app/controller/ChatController.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from fastapi import APIRouter, HTTPException, status
2+
from app.model.AgentModel import (
3+
ChatRequest,
4+
ChatResponse
5+
)
6+
from app.service.AgentService import AgentService
7+
import logging
8+
9+
logger = logging.getLogger(__name__)
10+
11+
router = APIRouter(
12+
prefix="/api/v1/chat",
13+
tags=["Chat"],
14+
responses={404: {"description": "Not found"}}
15+
)
16+
17+
agent_service = AgentService()
18+
19+
20+
@router.post("", response_model=ChatResponse)
21+
async def chat_with_gemini(chat_request: ChatRequest):
22+
"""
23+
Gemini와 자유롭게 대화하기
24+
25+
사용자의 메시지와 대화 히스토리를 받아 Gemini의 응답을 반환합니다.
26+
히스토리를 포함하여 요청하면 문맥을 유지한 대화가 가능합니다.
27+
28+
- **message**: 사용자의 현재 질문/메시지
29+
- **history**: 이전 대화 히스토리 (선택사항)
30+
"""
31+
try:
32+
chat_data = await agent_service.chat(chat_request)
33+
return ChatResponse(
34+
success=True,
35+
message="Chat completed successfully",
36+
data=chat_data
37+
)
38+
except Exception as e:
39+
logger.error(f"Error during chat: {e}")
40+
raise HTTPException(
41+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
42+
detail=str(e)
43+
)

‎app/llm/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .gemini_service import GeminiService
2+
3+
__all__ = ["GeminiService"]

0 commit comments

Comments
 (0)