shamim237 commited on
Commit
12f501a
·
verified ·
1 Parent(s): 8ff45d7

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -202
app.py DELETED
@@ -1,202 +0,0 @@
1
- import logging
2
- import asyncio
3
- import uuid
4
- from datetime import datetime
5
- from pathlib import Path
6
- from typing import Dict, Optional
7
-
8
- from fastapi import FastAPI, HTTPException, Request
9
- from fastapi.middleware.cors import CORSMiddleware
10
- from fastapi.responses import JSONResponse
11
- from pydantic import BaseModel, constr, Field, validator, constr
12
- from rag import generate_answer # Importing the function to generate answers
13
-
14
- # Create logs directory if it doesn't exist
15
- Path("logs").mkdir(exist_ok=True) # Ensure logs directory is available for logging
16
-
17
- # Initialize FastAPI app with metadata
18
- app = FastAPI(
19
- title="Question Answering API", # Title of the API
20
- description="API for generating answers using RAG", # Description of the API
21
- version="1.0.0", # Version of the API
22
- docs_url="/docs", # URL for API documentation
23
- redoc_url="/redoc" # URL for ReDoc documentation
24
- )
25
-
26
- # Configure CORS
27
- app.add_middleware(
28
- CORSMiddleware,
29
- allow_origins=["*"], # Allow all origins; modify in production for security
30
- allow_credentials=True, # Allow credentials to be included in requests
31
- allow_methods=["*"], # Allow all HTTP methods
32
- allow_headers=["*"], # Allow all headers
33
- )
34
-
35
- # Configure detailed logging
36
- logging.basicConfig(
37
- level=logging.INFO, # Set logging level to INFO
38
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # Log format
39
- handlers=[ # Handlers for logging output
40
- logging.StreamHandler(), # Log to console
41
- logging.FileHandler(f'logs/app_{datetime.now().strftime("%Y%m%d")}.log') # Log to file
42
- ]
43
- )
44
- logger = logging.getLogger(__name__) # Create a logger for this module
45
-
46
- def generate_request_id() -> str:
47
- """Generate a unique request ID.""" # Docstring for function
48
- return str(uuid.uuid4()) # Return a new UUID as a string
49
-
50
- class QuestionRequest(BaseModel):
51
- """Request model for question answering endpoint.""" # Docstring for model
52
- question: constr(min_length=1) = Field( # Field for the question with validation
53
- ...,
54
- description="The question to be answered", # Description of the field
55
- example="What is the capital of France?" # Example question
56
- )
57
-
58
- @validator('question') # Validator for the question field
59
- def validate_question(cls, v):
60
- if v.strip() == "": # Check if the question is empty
61
- raise HTTPException(
62
- status_code=500, # Raise HTTP 500 if empty
63
- detail="Error processing request" # Error message
64
- )
65
- return v.strip() # Return the trimmed question
66
-
67
- class ErrorResponse(BaseModel):
68
- """Standard error response model.""" # Docstring for error response model
69
- detail: str # Detail of the error
70
- request_id: Optional[str] = None # Optional request ID for tracking
71
-
72
- @app.middleware("http")
73
- async def add_request_id(request: Request, call_next):
74
- """Middleware to add request ID to all requests.""" # Docstring for middleware
75
- request_id = generate_request_id() # Generate a new request ID
76
- request.state.request_id = request_id # Store request ID in request state
77
- response = await call_next(request) # Process the request
78
- response.headers["X-Request-ID"] = request_id # Add request ID to response headers
79
- return response # Return the response
80
-
81
- @app.exception_handler(HTTPException)
82
- async def http_exception_handler(request: Request, exc: HTTPException):
83
- """Custom exception handler to include request ID.""" # Docstring for exception handler
84
- return JSONResponse(
85
- status_code=exc.status_code, # Return the status code from the exception
86
- content={"detail": exc.detail, "request_id": request.state.request_id} # Include error details and request ID
87
- )
88
-
89
- @app.post("/answer",
90
- response_model=Dict[str, str], # Response model for the endpoint
91
- summary="Generate an answer for the given question", # Summary of the endpoint
92
- response_description="Returns the generated answer", # Description of the response
93
- responses={ # Possible responses
94
- 400: {"model": ErrorResponse}, # Bad request response
95
- 500: {"model": ErrorResponse}, # Internal server error response
96
- 504: {"model": ErrorResponse} # Gateway timeout response
97
- }
98
- )
99
- async def get_answer(request: Request, question_request: QuestionRequest) -> Dict[str, str]:
100
- """
101
- Generate an answer for the given question.
102
-
103
- Args:
104
- request: FastAPI request object # Description of request argument
105
- question_request: The question request model # Description of question_request argument
106
-
107
- Returns:
108
- Dict containing the generated answer # Description of return value
109
-
110
- Raises:
111
- HTTPException: For various error conditions # Description of possible exceptions
112
- """
113
- request_id = request.state.request_id # Retrieve request ID from state
114
- logger.info("Processing request %s - Question: %s", request_id, question_request.question) # Log the processing request
115
-
116
- try:
117
- # Additional validation
118
- if len(question_request.question) > 1000: # Check if question exceeds max length
119
- logger.warning("Request %s: Question exceeds maximum length", request_id) # Log warning
120
- raise HTTPException(
121
- status_code=400, # Raise HTTP 400 for bad request
122
- detail="Question length exceeds maximum allowed characters (1000)" # Error message
123
- )
124
-
125
- # Convert generate_answer to async if it's not already
126
- async def async_generate_answer(question: str):
127
- loop = asyncio.get_event_loop() # Get the current event loop
128
- return await loop.run_in_executor(None, generate_answer, question) # Run the generate_answer function in executor
129
-
130
- # Generate answer with timeout handling
131
- answer = await asyncio.wait_for(
132
- async_generate_answer(question_request.question), # Await the answer generation
133
- timeout=120.0 # 120 second timeout
134
- )
135
-
136
- logger.info("Request %s: Successfully generated answer", request_id) # Log successful answer generation
137
- return {"answer": answer} # Return the generated answer
138
-
139
- except asyncio.TimeoutError: # Handle timeout errors
140
- logger.error("Request %s: Generation timeout", request_id) # Log timeout error
141
- raise HTTPException(
142
- status_code=504, # Raise HTTP 504 for timeout
143
- detail="Answer generation timed out" # Error message
144
- )
145
-
146
- except ValueError as ve: # Handle value errors
147
- logger.error("Request %s: Validation error - %s", request_id, str(ve)) # Log validation error
148
- raise HTTPException(
149
- status_code=400, # Raise HTTP 400 for bad request
150
- detail=str(ve) # Return the validation error message
151
- )
152
-
153
- except Exception as e: # Handle all other exceptions
154
- logger.error(
155
- "Request %s: Unexpected error - %s",
156
- request_id,
157
- str(e),
158
- exc_info=True # Include stack trace in logs
159
- )
160
- raise HTTPException(
161
- status_code=500, # Raise HTTP 500 for internal server error
162
- detail="Internal server error occurred. Please try again later." # Error message
163
- )
164
-
165
- @app.get("/health",
166
- summary="Health check endpoint", # Summary of the health check endpoint
167
- response_description="Returns the API health status" # Description of the response
168
- )
169
- async def health_check():
170
- """Health check endpoint to verify API is running.""" # Docstring for health check
171
- return {"status": "healthy"} # Return health status
172
-
173
- @app.on_event("startup")
174
- async def startup_event():
175
- """Initialize any resources on startup.""" # Docstring for startup event
176
- logger.info("Starting up Question Answering API") # Log startup event
177
- # Add any initialization code here (e.g., loading models)
178
-
179
- @app.on_event("shutdown")
180
- async def shutdown_event():
181
- """Cleanup any resources on shutdown.""" # Docstring for shutdown event
182
- logger.info("Shutting down Question Answering API") # Log shutdown event
183
- # Add cleanup code here
184
-
185
- if __name__ == "__main__": # Entry point for the application
186
- import uvicorn # Import Uvicorn for running the app
187
-
188
- # Load configuration from environment variables or use defaults
189
- host = "0.0.0.0" # Host address
190
- port = 8000 # Port number
191
-
192
- logger.info(f"Starting server on {host}:{port}") # Log server start
193
-
194
- uvicorn.run(
195
- "app:app", # Application to run
196
- host=host, # Host address
197
- port=port, # Port number
198
- reload=False, # Disable auto-reload in production
199
- log_level="info", # Set log level
200
- access_log=True, # Enable access logging
201
- workers=1 # Number of worker processes
202
- )