Spaces:
Sleeping
Sleeping
| # --- IMPORTS --- | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from fastapi import FastAPI, Request | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.templating import Jinja2Templates | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| import uvicorn | |
| # NEW, CRITICAL IMPORT for running behind a proxy | |
| from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware | |
| # --- ADD THIS BLOCK TO FIX 'ModuleNotFoundError' --- | |
| # This adds the 'src' directory to the Python path | |
| # so it can find the cnnClassifier package in the Docker container. | |
| sys.path.append(str(Path(__file__).parent / "src")) | |
| # ---------------------------------------------------- | |
| # Now we can import your custom ML components | |
| from cnnClassifier.utils.common import decodeImage | |
| from cnnClassifier.pipeline.prediction import PredictionPipeline | |
| # --- CONFIGURATION --- | |
| os.putenv('LANG', 'en_US.UTF-8') | |
| os.putenv('LC_ALL', 'en_US.UTF-8') | |
| # --- INITIALIZE FastAPI APP --- | |
| app = FastAPI( | |
| title="Chest Cancer Classification API", | |
| description="An API to predict whether a chest CT scan shows signs of adenocarcinoma cancer." | |
| ) | |
| # --- ADD PROXY MIDDLEWARE (FIXES HTTPS/MIXED CONTENT ERROR) --- | |
| # This middleware is essential for running behind a reverse proxy like Hugging Face Spaces. | |
| # It tells the app to trust the 'x-forwarded-proto' header from the proxy. | |
| app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*") | |
| # ------------------------------------------------------------ | |
| # --- MIDDLEWARE (for CORS) --- | |
| # This should come AFTER the ProxyHeadersMiddleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # --- MOUNT STATIC FILES AND TEMPLATES --- | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| templates = Jinja2Templates(directory="templates") | |
| # --- LOAD THE PREDICTION PIPELINE ON STARTUP --- | |
| classifier = PredictionPipeline(filename="inputImage.jpg") | |
| # --- DEFINE THE REQUEST BODY STRUCTURE --- | |
| class ImagePayload(BaseModel): | |
| image: str | |
| # --- API ENDPOINTS --- | |
| async def home(request: Request): | |
| """Renders the main user interface (index.html).""" | |
| return templates.TemplateResponse("index.html", {"request": request}) | |
| async def trainRoute(): | |
| """Triggers the DVC pipeline to retrain the model.""" | |
| os.system("dvc repro") | |
| return {"message": "Training done successfully!"} | |
| async def predictRoute(payload: ImagePayload): | |
| """ | |
| Accepts a base64 encoded image, saves it to a temporary location, | |
| runs prediction, and returns the result. | |
| """ | |
| # --- THIS IS THE FIX --- | |
| # Define a writable filename inside the /tmp directory. | |
| temp_image_path = "/tmp/inputImage.jpg" | |
| # 1. Decode the image and save it to the temporary path | |
| decodeImage(payload.image, temp_image_path) | |
| # 2. Update the classifier's filename to the new temporary path and predict | |
| classifier.filename = temp_image_path | |
| prediction_value = classifier.predict() | |
| # ---------------------- | |
| # 3. Translate the numeric prediction into a human-readable string | |
| if prediction_value == 1: | |
| prediction_text = "Normal" | |
| else: | |
| prediction_text = "Cancer" | |
| # 4. Return the result | |
| return [{"prediction": prediction_text}] | |
| # --- RUN THE APP --- | |
| if __name__ == "__main__": | |
| # Note: Hugging Face uses port 7860 by default for its apps | |
| uvicorn.run(app, host="0.0.0.0", port=7860) |