Spaces:
Running
Running
File size: 2,873 Bytes
a874986 f84688d a874986 f84688d a874986 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
#!/usr/bin/env python3
"""
FetalCLIP Server for Hugging Face Spaces
This server:
1. Serves the React frontend as static files
2. Runs the FastAPI backend API
3. Runs on port 7860 (HF Spaces requirement)
"""
import sys
from pathlib import Path
# Add backend to path
sys.path.insert(0, str(Path(__file__).parent / "backend"))
import uvicorn
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
# Import the backend app components
from app.routes import classification_router, gestational_age_router, feedback_router
from app.services.model import model_service
# Assets directory
ASSETS_DIR = Path(__file__).parent / "assets"
STATIC_DIR = Path(__file__).parent / "backend" / "static"
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Load model on startup."""
print("๐ Starting FetalCLIP on Hugging Face Spaces...")
print(f"๐ Assets directory: {ASSETS_DIR}")
model_service.load_model(ASSETS_DIR)
yield
print("๐ Shutting down FetalCLIP...")
# Create the app
app = FastAPI(
title="FetalCLIP API",
description="Foundation Model for Fetal Ultrasound Analysis - Hugging Face Spaces Edition",
version="1.0.0",
lifespan=lifespan,
)
# CORS for HF Spaces
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # HF Spaces needs permissive CORS
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include API routers
app.include_router(classification_router)
app.include_router(gestational_age_router)
app.include_router(feedback_router)
# Health check endpoint
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"model_loaded": model_service.model is not None,
"device": str(model_service.device),
"available_views": len(model_service.list_plane),
"platform": "huggingface-spaces"
}
# Serve React frontend
if STATIC_DIR.exists():
# Mount static assets (JS, CSS, etc.)
app.mount("/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="static-assets")
# Serve index.html for all non-API routes (SPA routing)
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
# If it's an API route, skip
if full_path.startswith("api/") or full_path == "health" or full_path == "docs":
return None
# Serve index.html for SPA routing
index_path = STATIC_DIR / "index.html"
if index_path.exists():
return FileResponse(index_path)
return {"error": "Frontend not built"}
if __name__ == "__main__":
# HF Spaces requires port 7860
uvicorn.run(
app,
host="0.0.0.0",
port=7860,
reload=False
)
|