import torch import io from pathlib import Path from fastapi import FastAPI, File, UploadFile, Form from fastapi.responses import HTMLResponse from PIL import Image from torchvision import transforms import uvicorn from train import BoneAgeModel app = FastAPI(title="Bone Age Assessment") device = torch.device("cpu") # CPU only for Render free tier model = None use_fp16 = False # Try fp16 model first (smaller memory), fallback to full model for model_file in ["best_model_fp16.pth", "best_model.pth"]: model_path = Path(model_file) if model_path.exists(): m = BoneAgeModel() if model_file == "best_model_fp16.pth": m = m.half() use_fp16 = True m.load_state_dict(torch.load(model_path, map_location="cpu")) m.eval() model = m print(f"Model loaded: {model_file}") break if model is None: print("No trained model found") transform = transforms.Compose([ transforms.Resize((256, 256)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) def predict_bone_age(image: Image.Image, is_male: bool) -> float: img_tensor = transform(image.convert("RGB")).unsqueeze(0).to(device) gender_tensor = torch.tensor([1.0 if is_male else 0.0]).to(device) if use_fp16: img_tensor = img_tensor.half() gender_tensor = gender_tensor.half() with torch.no_grad(): prediction = model(img_tensor, gender_tensor) return prediction.item() @app.get("/", response_class=HTMLResponse) async def home(): return """
Upload a hand X-ray to estimate skeletal maturity
Developed by Dr. Prashanth Mamidipalli