Spaces:
Runtime error
Runtime error
| from fastapi import FastAPI, UploadFile, File, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from contextlib import asynccontextmanager | |
| import torch | |
| import uvicorn | |
| from app.predictor import ProteinPredictor | |
| from app.schemas import PredictionResponse, HealthResponse | |
| # ββ Global predictor instance ββββββββββββββββββββββββββββββββββββββββββββββ | |
| predictor: ProteinPredictor = None | |
| async def lifespan(app: FastAPI): | |
| """Load model once at startup, release on shutdown.""" | |
| global predictor | |
| print("π Loading model...") | |
| predictor = ProteinPredictor() | |
| predictor.load() | |
| print("β Model ready!") | |
| yield | |
| print("π Shutting down...") | |
| # ββ App βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| app = FastAPI( | |
| title="Protein Function Prediction API", | |
| description="Predicts GO terms for a protein given its FASTA sequence using GraphSAGE + ESM2.", | |
| version="1.0.0", | |
| lifespan=lifespan, | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ββ Routes βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def health(): | |
| """Check that the API and model are up.""" | |
| return HealthResponse( | |
| status="ok", | |
| model_loaded=predictor is not None and predictor.is_ready, | |
| device=str(predictor.device) if predictor else "unknown", | |
| ) | |
| async def predict(file: UploadFile = File(..., description="FASTA file (.fasta or .fa)")): | |
| """ | |
| Upload a FASTA file and get predicted GO terms. | |
| - Accepts single or multi-sequence FASTA files. | |
| - Returns GO term IDs + their confidence scores. | |
| - Threshold: 0.5 (configurable via config.py). | |
| """ | |
| if not file.filename.endswith((".fasta", ".fa", ".txt")): | |
| raise HTTPException(status_code=400, detail="File must be a .fasta or .fa file.") | |
| content = await file.read() | |
| try: | |
| fasta_text = content.decode("utf-8") | |
| except UnicodeDecodeError: | |
| raise HTTPException(status_code=400, detail="Could not decode file. Make sure it's a valid FASTA text file.") | |
| if not fasta_text.strip(): | |
| raise HTTPException(status_code=400, detail="File is empty.") | |
| try: | |
| result = predictor.predict(fasta_text) | |
| except ValueError as e: | |
| raise HTTPException(status_code=422, detail=str(e)) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Prediction failed: {str(e)}") | |
| return result | |
| if __name__ == "__main__": | |
| uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=False) | |