s4um1l commited on
Commit
4b9a663
·
1 Parent(s): 7bae51f

vibe coding the fix now basically added more logs and timeouts

Browse files
Files changed (3) hide show
  1. Dockerfile +2 -4
  2. backend/main.py +67 -32
  3. frontend/src/App.js +7 -0
Dockerfile CHANGED
@@ -69,7 +69,5 @@ WORKDIR /home/user/app/backend
69
  # Expose port for FastAPI on Hugging Face
70
  EXPOSE 7860
71
 
72
- # Start the FastAPI server
73
- # CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
74
- # Update this line in your Dockerfile
75
- CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860", "--proxy-headers", "--forwarded-allow-ips=*"]
 
69
  # Expose port for FastAPI on Hugging Face
70
  EXPOSE 7860
71
 
72
+ # Start the FastAPI server with optimized settings for Hugging Face Spaces
73
+ CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860", "--proxy-headers", "--forwarded-allow-ips=*", "--timeout-keep-alive", "75"]
 
 
backend/main.py CHANGED
@@ -34,32 +34,50 @@ from aimakerspace.utils.session_manager import SessionManager
34
  from dotenv import load_dotenv
35
  load_dotenv()
36
 
37
- app = FastAPI()
 
 
 
 
 
38
 
39
- # For deployment on Hugging Face Spaces, add a middleware to handle HTTPS
40
  from starlette.middleware.base import BaseHTTPMiddleware
 
41
 
42
- class HTTPSRedirectMiddleware(BaseHTTPMiddleware):
43
  async def dispatch(self, request, call_next):
44
- # Check for X-Forwarded-Proto header and ensure it's HTTPS
45
- if request.headers.get("X-Forwarded-Proto") == "http":
46
- logger.info("Redirecting to HTTPS")
47
- url = request.url.replace(scheme="https")
48
- return RedirectResponse(url=str(url), status_code=307)
49
- return await call_next(request)
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- # Add the HTTPS middleware
52
- from starlette.responses import RedirectResponse
53
- app.add_middleware(HTTPSRedirectMiddleware)
54
 
55
- # Configure CORS - allow all origins explicitly for development
56
  app.add_middleware(
57
  CORSMiddleware,
58
- allow_origins=["*"], # This will allow all origins
59
  allow_credentials=True,
60
- allow_methods=["*"], # Allow all methods
61
- allow_headers=["*"], # Allow all headers
62
- expose_headers=["*"]
 
63
  )
64
 
65
  # Initialize session manager
@@ -167,6 +185,11 @@ async def process_file_background(temp_path: str, filename: str, session_id: str
167
  async def upload_file(background_tasks: BackgroundTasks, file: UploadFile = File(...)):
168
  try:
169
  logger.info(f"Received upload request for file: {file.filename}")
 
 
 
 
 
170
 
171
  # Check file size first
172
  file_size = 0
@@ -174,20 +197,32 @@ async def upload_file(background_tasks: BackgroundTasks, file: UploadFile = File
174
  contents = bytearray()
175
 
176
  # Read file in chunks to avoid memory issues
177
- while True:
178
- chunk = await file.read(chunk_size)
179
- if not chunk:
180
- break
181
- file_size += len(chunk)
182
- contents.extend(chunk)
183
-
184
- # Check size limit
185
- if file_size > FILE_SIZE_LIMIT:
186
- logger.warning(f"File too large: {file_size/1024/1024:.2f}MB exceeds limit of {FILE_SIZE_LIMIT/1024/1024}MB")
187
- return HTTPException(
188
- status_code=413,
189
- detail=f"File too large. Maximum size is {FILE_SIZE_LIMIT/1024/1024}MB"
190
- )
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
  logger.info(f"File size: {file_size/1024/1024:.2f}MB")
193
 
@@ -214,7 +249,7 @@ async def upload_file(background_tasks: BackgroundTasks, file: UploadFile = File
214
  session_id
215
  )
216
 
217
- return {"session_id": session_id, "message": "File uploaded and processing started"}
218
 
219
  except Exception as e:
220
  logger.error(f"Error processing upload: {str(e)}")
 
34
  from dotenv import load_dotenv
35
  load_dotenv()
36
 
37
+ app = FastAPI(
38
+ title="RAG Application",
39
+ description="Retrieval Augmented Generation with FastAPI and React",
40
+ version="0.1.0",
41
+ root_path="", # Important for proxy environments
42
+ )
43
 
44
+ # More robust middleware for handling HTTPS
45
  from starlette.middleware.base import BaseHTTPMiddleware
46
+ from starlette.responses import RedirectResponse, JSONResponse
47
 
48
+ class ProxyMiddleware(BaseHTTPMiddleware):
49
  async def dispatch(self, request, call_next):
50
+ # Log request details for debugging
51
+ logger.info(f"Request path: {request.url.path}")
52
+ logger.info(f"Request headers: {request.headers}")
53
+
54
+ # Validate request before processing
55
+ try:
56
+ start_time = time.time()
57
+ response = await call_next(request)
58
+ process_time = time.time() - start_time
59
+ response.headers["X-Process-Time"] = str(process_time)
60
+ return response
61
+ except Exception as e:
62
+ logger.error(f"Request failed: {str(e)}")
63
+ logger.error(traceback.format_exc())
64
+ return JSONResponse(
65
+ status_code=500,
66
+ content={"detail": f"Internal server error: {str(e)}"}
67
+ )
68
 
69
+ # Add custom middleware
70
+ app.add_middleware(ProxyMiddleware)
 
71
 
72
+ # Configure CORS - more specific configuration for Hugging Face
73
  app.add_middleware(
74
  CORSMiddleware,
75
+ allow_origins=["*"], # In production, you should restrict this
76
  allow_credentials=True,
77
+ allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
78
+ allow_headers=["*"],
79
+ expose_headers=["Content-Length", "X-Process-Time"],
80
+ max_age=600, # 10 minutes cache for preflight requests
81
  )
82
 
83
  # Initialize session manager
 
185
  async def upload_file(background_tasks: BackgroundTasks, file: UploadFile = File(...)):
186
  try:
187
  logger.info(f"Received upload request for file: {file.filename}")
188
+ logger.info(f"Content type: {file.content_type}")
189
+
190
+ # Create a unique ID for this upload
191
+ upload_id = str(uuid.uuid4())
192
+ logger.info(f"Assigned upload ID: {upload_id}")
193
 
194
  # Check file size first
195
  file_size = 0
 
197
  contents = bytearray()
198
 
199
  # Read file in chunks to avoid memory issues
200
+ try:
201
+ while True:
202
+ chunk = await asyncio.wait_for(file.read(chunk_size), timeout=60.0)
203
+ if not chunk:
204
+ break
205
+ file_size += len(chunk)
206
+ contents.extend(chunk)
207
+
208
+ # Check size limit
209
+ if file_size > FILE_SIZE_LIMIT:
210
+ logger.warning(f"File too large: {file_size/1024/1024:.2f}MB exceeds limit of {FILE_SIZE_LIMIT/1024/1024}MB")
211
+ return HTTPException(
212
+ status_code=413,
213
+ detail=f"File too large. Maximum size is {FILE_SIZE_LIMIT/1024/1024}MB"
214
+ )
215
+
216
+ # Log progress for large files
217
+ if file_size % (5 * 1024 * 1024) == 0: # Log every 5MB
218
+ logger.info(f"Upload progress: {file_size/1024/1024:.2f}MB read so far...")
219
+
220
+ except asyncio.TimeoutError:
221
+ logger.error(f"Timeout reading file: {file.filename}")
222
+ raise HTTPException(
223
+ status_code=408,
224
+ detail="Request timeout while reading file. Please try again."
225
+ )
226
 
227
  logger.info(f"File size: {file_size/1024/1024:.2f}MB")
228
 
 
249
  session_id
250
  )
251
 
252
+ return {"session_id": session_id, "message": "File uploaded and processing started", "upload_id": upload_id}
253
 
254
  except Exception as e:
255
  logger.error(f"Error processing upload: {str(e)}")
frontend/src/App.js CHANGED
@@ -197,9 +197,16 @@ function FileUploader({ onFileUpload }) {
197
  headers: {
198
  'Content-Type': 'multipart/form-data',
199
  },
 
 
 
200
  onUploadProgress: (progressEvent) => {
201
  const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
202
  setUploadProgress(percentCompleted);
 
 
 
 
203
  }
204
  });
205
 
 
197
  headers: {
198
  'Content-Type': 'multipart/form-data',
199
  },
200
+ timeout: 180000, // 3 minutes timeout for large files
201
+ maxContentLength: Infinity,
202
+ maxBodyLength: Infinity,
203
  onUploadProgress: (progressEvent) => {
204
  const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
205
  setUploadProgress(percentCompleted);
206
+ },
207
+ // Add retry logic for network errors
208
+ validateStatus: function (status) {
209
+ return status >= 200 && status < 500; // Handle 4xx errors in our own logic
210
  }
211
  });
212