cevheri commited on
Commit
e54adcc
·
1 Parent(s): d0a1fcb

feat: enhance api_response decorator with improved error handling and logging

Browse files
Files changed (3) hide show
  1. app/api/chat_api.py +34 -17
  2. app/core/api_response.py +29 -10
  3. main.py +2 -2
app/api/chat_api.py CHANGED
@@ -1,25 +1,27 @@
1
  # chat api
2
 
3
  from typing import List
4
- from fastapi import APIRouter, HTTPException, Depends
5
  from app.schema.chat_schema import ChatCompletionRequest, ChatCompletionResponse, MessageResponse, PlotResponse
6
  from app.schema.conversation import ConversationResponse, ConversationItemResponse
7
  from app.service.chat_service import ChatService
8
  from app.security.auth_service import AuthService
9
  from app.core.api_response import api_response
10
-
11
 
12
  router = APIRouter(prefix="/v1", tags=["chat"])
13
  service = ChatService()
14
  auth_service = AuthService()
15
 
 
 
16
  ################
17
  # chat completion api list
18
  ################
19
  # create a chat completion
20
- @api_response()
21
  @router.post("/chat/completions", response_model=ChatCompletionResponse)
22
- async def create_chat_completion(req: ChatCompletionRequest, username: str = Depends(auth_service.verify_credentials)):
 
23
  """
24
  Chat completion API - Given a list of messages comprising a conversation, the model will return a response.
25
  If completion_id is not provided, start a new chat completion by providing a list of messages.
@@ -27,14 +29,15 @@ async def create_chat_completion(req: ChatCompletionRequest, username: str = Dep
27
  Summary: question -> Send button from chat interface(UI)
28
  """
29
  try:
30
- return await service.handle_chat_completion(req)
31
  except Exception as e:
32
  raise HTTPException(status_code=500, detail=str(e))
33
 
34
 
35
  # get all chat completions
36
  @router.get("/chat/completions", response_model=List[ChatCompletionResponse])
37
- async def list_chat_completions(username: str = Depends(auth_service.verify_credentials)):
 
38
  """
39
  Get all chat completions
40
  Summary: First load the chat interface(UI) for list of chat completions on the left side.
@@ -52,9 +55,10 @@ async def list_chat_completions(username: str = Depends(auth_service.verify_cred
52
  raise HTTPException(status_code=500, detail=str(e))
53
 
54
 
55
- # get a chat completion by id
56
  @router.get("/chat/completions/{completion_id}", response_model=ChatCompletionResponse)
57
- async def retrieve_chat_completion(completion_id: str, username: str = Depends(auth_service.verify_credentials)):
 
58
  """
59
  Get a chat completion by id
60
  Summary: Click on a chat completion on the left side to load the chat completion on the right side.
@@ -65,9 +69,10 @@ async def retrieve_chat_completion(completion_id: str, username: str = Depends(a
65
  raise HTTPException(status_code=500, detail=str(e))
66
 
67
 
68
- # get all messages for a chat completion
69
  @router.get("/chat/completions/{completion_id}/messages", response_model=List[MessageResponse])
70
- async def list_messages(completion_id: str, username: str = Depends(auth_service.verify_credentials)):
 
71
  """
72
  Get all messages for a chat completion
73
  Summary: Click on a chat completion on the left side to load the chat completion on the right side.
@@ -81,9 +86,10 @@ async def list_messages(completion_id: str, username: str = Depends(auth_service
81
  ################
82
  # plot api list
83
  ################
84
- # get a plot for a message
85
  @router.get("/chat/completions/{completion_id}/messages/{message_id}/plot", response_model=PlotResponse)
86
- async def retrieve_plot(completion_id: str, message_id: str, username: str = Depends(auth_service.verify_credentials)):
 
87
  """
88
  Get a plot figure for a message to visualize the data
89
  Summary: Click on a message on the right side to load the plot on the right side.
@@ -101,24 +107,35 @@ async def retrieve_plot(completion_id: str, message_id: str, username: str = Dep
101
  # GET https://chatgpt.com/backend-api/conversations/{completion_id}
102
 
103
 
104
- # get all conversations
105
- @api_response()
106
  @router.get("/conversations", response_model=ConversationResponse)
107
- async def list_conversations(username: str = Depends(auth_service.verify_credentials)):
 
108
  """
109
  Get all conversations
110
  """
 
111
  try:
112
- return await service.find_all_conversations(username)
 
 
 
 
 
 
113
  except Exception as e:
 
114
  raise HTTPException(status_code=500, detail=str(e))
115
 
116
  # get a conversation by id
 
117
  @router.get("/conversations/{completion_id}", response_model=ConversationItemResponse)
118
- async def retrieve_conversation(completion_id: str, username: str = Depends(auth_service.verify_credentials)):
 
119
  """
120
  Get a conversation by id
121
  """
 
122
  try:
123
  return await service.find_conversation_by_id(completion_id)
124
  except Exception as e:
 
1
  # chat api
2
 
3
  from typing import List
4
+ from fastapi import APIRouter, HTTPException, Depends, Request
5
  from app.schema.chat_schema import ChatCompletionRequest, ChatCompletionResponse, MessageResponse, PlotResponse
6
  from app.schema.conversation import ConversationResponse, ConversationItemResponse
7
  from app.service.chat_service import ChatService
8
  from app.security.auth_service import AuthService
9
  from app.core.api_response import api_response
10
+ from loguru import logger
11
 
12
  router = APIRouter(prefix="/v1", tags=["chat"])
13
  service = ChatService()
14
  auth_service = AuthService()
15
 
16
+
17
+
18
  ################
19
  # chat completion api list
20
  ################
21
  # create a chat completion
 
22
  @router.post("/chat/completions", response_model=ChatCompletionResponse)
23
+ @api_response()
24
+ async def create_chat_completion(chat_completion: ChatCompletionRequest, request: Request, username: str = Depends(auth_service.verify_credentials)):
25
  """
26
  Chat completion API - Given a list of messages comprising a conversation, the model will return a response.
27
  If completion_id is not provided, start a new chat completion by providing a list of messages.
 
29
  Summary: question -> Send button from chat interface(UI)
30
  """
31
  try:
32
+ return await service.handle_chat_completion(chat_completion)
33
  except Exception as e:
34
  raise HTTPException(status_code=500, detail=str(e))
35
 
36
 
37
  # get all chat completions
38
  @router.get("/chat/completions", response_model=List[ChatCompletionResponse])
39
+ @api_response()
40
+ async def list_chat_completions(request: Request, username: str = Depends(auth_service.verify_credentials)):
41
  """
42
  Get all chat completions
43
  Summary: First load the chat interface(UI) for list of chat completions on the left side.
 
55
  raise HTTPException(status_code=500, detail=str(e))
56
 
57
 
58
+ # get a chat completion by id
59
  @router.get("/chat/completions/{completion_id}", response_model=ChatCompletionResponse)
60
+ @api_response()
61
+ async def retrieve_chat_completion(completion_id: str, request: Request, username: str = Depends(auth_service.verify_credentials)):
62
  """
63
  Get a chat completion by id
64
  Summary: Click on a chat completion on the left side to load the chat completion on the right side.
 
69
  raise HTTPException(status_code=500, detail=str(e))
70
 
71
 
72
+ # get all messages for a chat completion
73
  @router.get("/chat/completions/{completion_id}/messages", response_model=List[MessageResponse])
74
+ @api_response()
75
+ async def list_messages(completion_id: str, request: Request, username: str = Depends(auth_service.verify_credentials)):
76
  """
77
  Get all messages for a chat completion
78
  Summary: Click on a chat completion on the left side to load the chat completion on the right side.
 
86
  ################
87
  # plot api list
88
  ################
89
+ # get a plot for a message
90
  @router.get("/chat/completions/{completion_id}/messages/{message_id}/plot", response_model=PlotResponse)
91
+ @api_response()
92
+ async def retrieve_plot(completion_id: str, message_id: str, request: Request, username: str = Depends(auth_service.verify_credentials)):
93
  """
94
  Get a plot figure for a message to visualize the data
95
  Summary: Click on a message on the right side to load the plot on the right side.
 
107
  # GET https://chatgpt.com/backend-api/conversations/{completion_id}
108
 
109
 
110
+ # get all conversations
 
111
  @router.get("/conversations", response_model=ConversationResponse)
112
+ @api_response()
113
+ async def list_conversations(request: Request, username: str = Depends(auth_service.verify_credentials)):
114
  """
115
  Get all conversations
116
  """
117
+ logger.debug(f"Listing conversations for username: {username}")
118
  try:
119
+ #return await service.find_all_conversations(username)
120
+ return {
121
+ "items": [],
122
+ "total": 0,
123
+ "limit": 10,
124
+ "offset": 0
125
+ }
126
  except Exception as e:
127
+ logger.error(f"Error in list_conversations: {str(e)}")
128
  raise HTTPException(status_code=500, detail=str(e))
129
 
130
  # get a conversation by id
131
+
132
  @router.get("/conversations/{completion_id}", response_model=ConversationItemResponse)
133
+ @api_response()
134
+ async def retrieve_conversation(completion_id: str, request: Request, username: str = Depends(auth_service.verify_credentials)):
135
  """
136
  Get a conversation by id
137
  """
138
+ logger.debug(f"Retrieving conversation with completion_id: {completion_id}")
139
  try:
140
  return await service.find_conversation_by_id(completion_id)
141
  except Exception as e:
app/core/api_response.py CHANGED
@@ -68,20 +68,39 @@ def get_mock_response(url_path: str, method: str) -> Dict:
68
  def api_response():
69
  """Decorator to handle mock/real API responses."""
70
  def decorator(func):
 
71
  @wraps(func)
72
  async def wrapper(request: Request, *args, **kwargs):
73
- url_path = request.url.path
74
- method = request.method
75
- logger.debug(f"BEGIN: url_path: {url_path} method: {method}")
 
 
 
 
 
 
 
 
 
76
  if USE_MOCK:
77
  logger.warning("Using mock response")
78
- result = get_mock_response(url_path, method)
79
- logger.trace(f"END: result: {result}")
80
- return result
 
 
 
 
81
  else:
82
- # Call original function for real response
83
- result = await func(request, *args, **kwargs)
84
- logger.trace(f"END: result: {result}")
85
- return result
 
 
 
 
 
86
  return wrapper
87
  return decorator
 
68
  def api_response():
69
  """Decorator to handle mock/real API responses."""
70
  def decorator(func):
71
+ logger.debug(f"BEGIN: decorator: {func}")
72
  @wraps(func)
73
  async def wrapper(request: Request, *args, **kwargs):
74
+ logger.debug(f"BEGIN: wrapper: {request}")
75
+ if not request:
76
+ logger.error("Request object not found in args or kwargs")
77
+ raise HTTPException(
78
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
79
+ detail="Request object not found"
80
+ )
81
+
82
+ logger.debug(f"USE_MOCK value: {USE_MOCK}")
83
+ logger.debug(f"Request path: {request.url.path}")
84
+ logger.debug(f"Request method: {request.method}")
85
+
86
  if USE_MOCK:
87
  logger.warning("Using mock response")
88
+ try:
89
+ result = get_mock_response(request.url.path, request.method)
90
+ logger.debug(f"Mock response: {result}")
91
+ return result
92
+ except Exception as e:
93
+ logger.error(f"Error getting mock response: {str(e)}")
94
+ raise
95
  else:
96
+ logger.warning("Using real response")
97
+ try:
98
+ result = await func(*args, **kwargs)
99
+ logger.debug(f"Real response: {result}")
100
+ return result
101
+ except Exception as e:
102
+ logger.error(f"Error getting real response: {str(e)}")
103
+ raise
104
+
105
  return wrapper
106
  return decorator
main.py CHANGED
@@ -9,8 +9,7 @@ from app.db.client import mongodb
9
 
10
  env = Env()
11
  env.read_env()
12
-
13
- USE_MOCK = env.bool("USE_MOCK", False)
14
  STORAGE_TYPE = env.str("STORAGE_TYPE", "mongodb")
15
 
16
 
@@ -74,6 +73,7 @@ app = FastAPI(
74
  openapi_url= "/openapi.json",
75
  lifespan= lifespan,
76
  openapi_tags= openapi_tags,
 
77
  )
78
 
79
  # Configure OpenAPI security scheme
 
9
 
10
  env = Env()
11
  env.read_env()
12
+
 
13
  STORAGE_TYPE = env.str("STORAGE_TYPE", "mongodb")
14
 
15
 
 
73
  openapi_url= "/openapi.json",
74
  lifespan= lifespan,
75
  openapi_tags= openapi_tags,
76
+ debug= True,
77
  )
78
 
79
  # Configure OpenAPI security scheme