Spaces:
Running
Running
Download app.py from sdmlai/plantdoc-api: direct link, hf CLI and curl.
- Browser
- Download file 4.01 kB
-
https://huggingface.co/spaces/sdmlai/plantdoc-api/resolve/main/app.py
- Command line
-
hf download hf://spaces/sdmlai/plantdoc-api/app.py
-
curl -L -o app.py https://huggingface.co/spaces/sdmlai/plantdoc-api/resolve/main/app.py
4.01 kB
| from fastapi import FastAPI, File, UploadFile, Query, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from plantdoc_predictor import Predictor | |
| from PIL import Image | |
| import io | |
| app = FastAPI(title="PlantDoc API", version="1.0.0") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| MODELS = [ | |
| {"name": "mobilenetv2_v1", "accuracy": 96.8, "description": "Mobile-optimized, fastest inference"}, | |
| {"name": "densenet169_v1", "accuracy": 99.68, "description": "Best classical CNN"}, | |
| {"name": "rec_add_attention_v1", "accuracy": 99.70, "description": "Best overall — Recursive Additive Attention (research model)"}, | |
| {"name": "convnext_small_v1", "accuracy": 99.50, "description": "High accuracy + efficient"}, | |
| {"name": "convnext_tiny_v1", "accuracy": 99.23, "description": "Lightweight ConvNeXt"}, | |
| {"name": "convnext_base_v1", "accuracy": 99.10, "description": "ConvNeXt base"}, | |
| {"name": "swin_tiny_patch4_window7", "accuracy": 99.10, "description": "Lightweight Swin Transformer"}, | |
| {"name": "swin_base_patch4_window7", "accuracy": 99.10, "description": "Swin Transformer"}, | |
| {"name": "vit_tiny_16_v1", "accuracy": 99.10, "description": "Lightweight Vision Transformer"}, | |
| {"name": "vit_small_16_v1", "accuracy": 99.10, "description": "Small Vision Transformer"}, | |
| {"name": "vit_base_16_v1", "accuracy": 99.10, "description": "Vision Transformer base"}, | |
| {"name": "vit_large_16_v1", "accuracy": 99.10, "description": "Vision Transformer large"}, | |
| {"name": "densenet121_v1", "accuracy": 98.68, "description": "Efficient DenseNet"}, | |
| {"name": "vgg19_v1", "accuracy": 98.98, "description": "Deep VGG"}, | |
| {"name": "inceptionv3_v1", "accuracy": 98.20, "description": "Multi-scale InceptionV3"}, | |
| {"name": "resnet50_v1", "accuracy": 97.80, "description": "Residual learning CNN"}, | |
| {"name": "efficientnetb50_v1", "accuracy": 97.80, "description": "EfficientNet balanced"}, | |
| {"name": "densenet210_v1", "accuracy": 97.00, "description": "Deep DenseNet"}, | |
| {"name": "vgg16_v1", "accuracy": 96.80, "description": "Classic CNN"}, | |
| {"name": "alexnet_v1", "accuracy": 92.80, "description": "Baseline CNN"}, | |
| ] | |
| MODEL_NAMES = [m["name"] for m in MODELS] | |
| _predictor_cache: dict[str, Predictor] = {} | |
| def get_predictor(model_name: str) -> Predictor: | |
| if model_name not in _predictor_cache: | |
| _predictor_cache[model_name] = Predictor(model_name=model_name, verbose=False) | |
| return _predictor_cache[model_name] | |
| def warmup(): | |
| get_predictor("mobilenetv2_v1") | |
| def health(): | |
| return {"status": "ok", "loaded_models": list(_predictor_cache.keys())} | |
| def list_models(): | |
| return {"models": MODELS} | |
| async def predict( | |
| file: UploadFile = File(...), | |
| model: str = Query(default="mobilenetv2_v1"), | |
| ): | |
| if model not in MODEL_NAMES: | |
| raise HTTPException(status_code=400, detail=f"Unknown model '{model}'. Call /models for the list.") | |
| content = await file.read() | |
| if len(content) == 0: | |
| raise HTTPException(status_code=400, detail="Empty file uploaded.") | |
| try: | |
| image = Image.open(io.BytesIO(content)).convert("RGB") | |
| except Exception: | |
| raise HTTPException(status_code=400, detail="Invalid image file.") | |
| try: | |
| predictor = get_predictor(model) | |
| result = predictor.predict(image) | |
| plant, disease = (result["label"].split("___") + [""])[:2] | |
| result["plant"] = plant.replace("_", " ") | |
| result["disease"] = disease.replace("_", " ") | |
| result["is_healthy"] = "healthy" in result["label"].lower() | |
| return result | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |