| # from fastapi import FastAPI, UploadFile, File | |
| # from fastapi.middleware.cors import CORSMiddleware | |
| # from predict_vitals import predict_vitals | |
| # import shutil | |
| # import os | |
| # app = FastAPI() | |
| # origins = [ | |
| # "http://localhost:5173" # frontend in development # your production frontend | |
| # ] | |
| # # ✅ Enable CORS | |
| # app.add_middleware( | |
| # CORSMiddleware, | |
| # allow_origins=origins, # Or restrict to ["http://localhost:5173"] | |
| # allow_credentials=True, | |
| # allow_methods=["*"], | |
| # allow_headers=["*"], | |
| # ) | |
| # @app.post("/analyze_video/") | |
| # async def analyze_video(file: UploadFile = File(...)): | |
| # try: | |
| # temp_dir = "uploads" | |
| # os.makedirs(temp_dir, exist_ok=True) | |
| # temp_path = os.path.join(temp_dir, file.filename) | |
| # with open(temp_path, "wb") as buffer: | |
| # shutil.copyfileobj(file.file, buffer) | |
| # result = predict_vitals(video_path=temp_path) | |
| # os.remove(temp_path) | |
| # print("Video received:", temp_path) | |
| # print("Model output:", result) | |
| # return result | |
| # except Exception as e: | |
| # return {"error": str(e)} | |
| # from fastapi import FastAPI, UploadFile, File, HTTPException | |
| # from fastapi.responses import JSONResponse | |
| # import uvicorn | |
| # import shutil | |
| # import os | |
| # import uuid | |
| # import logging | |
| # from predict_vitals import predict_vitals | |
| # # --- Basic Configuration --- | |
| # # Set up a logger for better debugging and monitoring in production | |
| # logging.basicConfig(level=logging.INFO) | |
| # logger = logging.getLogger(__name__) | |
| # # Create the FastAPI app instance | |
| # app = FastAPI( | |
| # title="BeatSync Vital Signs Model Service", | |
| # description="A dedicated API to analyze video files and extract heart rate and breathing rate using the MTTS-CAN model.", | |
| # version="1.0.0" | |
| # ) | |
| # # Define the directory to store temporary video files | |
| # TEMP_DIR = "temp_videos" | |
| # os.makedirs(TEMP_DIR, exist_ok=True) | |
| # # --- API Endpoint Definition --- | |
| # @app.post("/analyze_video/") | |
| # async def analyze_video(file: UploadFile = File(...)): | |
| # """ | |
| # This endpoint accepts a video file, processes it to predict vital signs | |
| # (heart rate and breathing rate), and returns the results. | |
| # """ | |
| # # Create a unique filename to prevent conflicts if multiple users upload at once | |
| # unique_filename = f"{uuid.uuid4()}_{file.filename}" | |
| # temp_video_path = os.path.join(TEMP_DIR, unique_filename) | |
| # try: | |
| # # --- 1. Save the uploaded video to a temporary file --- | |
| # logger.info(f"Receiving file: {file.filename}") | |
| # with open(temp_video_path, "wb") as buffer: | |
| # shutil.copyfileobj(file.file, buffer) | |
| # logger.info(f"File saved temporarily to: {temp_video_path}") | |
| # # --- 2. Call the core prediction logic from predict_vitals.py --- | |
| # logger.info("Starting vital signs prediction...") | |
| # # The predict_vitals function will handle preprocessing and model inference | |
| # result = predict_vitals(video_path=temp_video_path) | |
| # logger.info(f"Prediction successful. Result: {result}") | |
| # # --- 3. Validate the model's output --- | |
| # # Ensure the result is a dictionary and contains the expected keys | |
| # if not isinstance(result, dict) or "heart_rate" not in result or "breathing_rate" not in result: | |
| # logger.error(f"Invalid output format from model: {result}") | |
| # raise HTTPException( | |
| # status_code=500, | |
| # detail="Model produced an unexpected output format." | |
| # ) | |
| # # --- 4. Return the successful result --- | |
| # return JSONResponse( | |
| # status_code=200, | |
| # content=result | |
| # ) | |
| # except (IOError, ValueError, HTTPException) as e: | |
| # # Catch specific, known errors (e.g., video too short, no face detected) | |
| # logger.error(f"A known error occurred during processing: {e}") | |
| # # Forward the specific error message to the client | |
| # raise HTTPException(status_code=400, detail=str(e)) | |
| # except Exception as e: | |
| # # Catch any other unexpected errors during the process | |
| # logger.exception(f"An unexpected error occurred for file {file.filename}: {e}") | |
| # # Return a generic 500 Internal Server Error to hide implementation details | |
| # raise HTTPException( | |
| # status_code=500, | |
| # detail="An internal server error occurred during video analysis." | |
| # ) | |
| # finally: | |
| # # --- 5. Clean up the temporary file --- | |
| # # This block ensures the temporary video is deleted, even if an error occurred. | |
| # if os.path.exists(temp_video_path): | |
| # os.remove(temp_video_path) | |
| # logger.info(f"Cleaned up temporary file: {temp_video_path}") | |
| # # --- Health Check Endpoint --- | |
| # @app.get("/") | |
| # def read_root(): | |
| # """A simple health check endpoint to confirm the service is running.""" | |
| # return {"status": "Video Model Service is running"} | |
| # # --- To run this server locally for testing --- | |
| # # Use the command: uvicorn server:app --host 0.0.0.0 --port 8000 --reload | |
| # if __name__ == "__main__": | |
| # uvicorn.run(app, host="0.0.0.0", port=8000) | |
| # from fastapi import FastAPI, UploadFile, File, HTTPException | |
| # from fastapi.responses import JSONResponse | |
| # import uvicorn | |
| # import logging | |
| # from predict_vitals import predict_vitals | |
| # from fastapi.middleware.cors import CORSMiddleware # 1. ADD THIS IMPORT | |
| # app = FastAPI( | |
| # title="BeatSync Video Model Service", | |
| # description="An API to process video files and predict vital signs.", | |
| # version="1.0.0" | |
| # ) | |
| # # 2. ADD THIS ENTIRE BLOCK | |
| # # This allows your API Gateway on Render to communicate with this service. | |
| # # -------------------------------------------------------------------------- | |
| # app.add_middleware( | |
| # CORSMiddleware, | |
| # allow_origins=["*"], # Allows all origins | |
| # allow_credentials=True, | |
| # allow_methods=["*"], # Allows all methods | |
| # allow_headers=["*"], # Allows all headers | |
| # ) | |
| # # -------------------------------------------------------------------------- | |
| # logging.basicConfig(level=logging.INFO) | |
| # logger = logging.getLogger(__name__) | |
| # @app.post("/predict/") | |
| # async def predict(video: UploadFile = File(...)): | |
| # if not video.filename.endswith('.mp4'): | |
| # raise HTTPException(status_code=400, detail="Invalid file format. Please upload an MP4 video.") | |
| # try: | |
| # # Save the uploaded video file temporarily | |
| # video_path = f"/tmp/{video.filename}" | |
| # with open(video_path, "wb") as buffer: | |
| # buffer.write(await video.read()) | |
| # logger.info(f"Processing video: {video_path}") | |
| # # Get predictions | |
| # predictions = predict_vitals(video_path) | |
| # return JSONResponse(content=predictions) | |
| # except Exception as e: | |
| # logger.exception(f"An error occurred during prediction: {e}") | |
| # raise HTTPException(status_code=500, detail=str(e)) | |
| # @app.get("/") | |
| # def read_root(): | |
| # return {"status": "Video Model Service is running"} | |
| # if __name__ == "__main__": | |
| # uvicorn.run(app, host="0.0.0.0", port=8002) # This port is for local dev only | |
| from fastapi import FastAPI, UploadFile, File, HTTPException | |
| import uvicorn | |
| import logging | |
| import os | |
| from predict_vitals import predict_vitals | |
| from fastapi.middleware.cors import CORSMiddleware | |
| app = FastAPI() | |
| # This is critical: It allows your frontend on Render to call this service | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| async def predict(video: UploadFile = File(...)): | |
| video_path = f"/tmp/{os.urandom(8).hex()}_{video.filename}" | |
| try: | |
| with open(video_path, "wb") as buffer: | |
| buffer.write(await video.read()) | |
| logger.info(f"Processing video: {video_path}") | |
| predictions = predict_vitals(video_path) | |
| return predictions | |
| except Exception as e: | |
| logger.exception(f"An error occurred during prediction: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| finally: | |
| # This ensures the video is always deleted after processing | |
| if os.path.exists(video_path): | |
| os.remove(video_path) | |
| logger.info(f"Cleaned up temporary video file: {video_path}") | |
| def read_root(): | |
| return {"status": "Video Model Service is running"} |