agro-vision-api / api.py
Jeyzimtech's picture
Update api.py
c9eaea0 verified
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import torch
from torchvision import transforms
from torchvision.models import mobilenet_v3_large, MobileNet_V3_Large_Weights
from PIL import Image
import io
import os
app = FastAPI(title="AgroVision API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Load models safely
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
VERIFY_MODEL_PATH = os.path.join(SCRIPT_DIR, "Jverify_model.pth")
DISEASE_MODEL_PATH = os.path.join(SCRIPT_DIR, "Jmodel.pth")
# Global dict for caching
MODELS = {
"verify": None,
"verify_classes": [],
"disease": None,
"disease_classes": []
}
def load_model(path):
if not os.path.exists(path):
return None, []
checkpoint = torch.load(path, map_location=device)
classes = checkpoint['classes']
model = mobilenet_v3_large(weights=MobileNet_V3_Large_Weights.IMAGENET1K_V1)
model.classifier[3] = torch.nn.Linear(model.classifier[3].in_features, len(classes))
model.load_state_dict(checkpoint['mobilenet'])
model = model.to(device)
model.eval()
return model, classes
@app.on_event("startup")
def startup_event():
print("Loading models...")
MODELS["verify"], MODELS["verify_classes"] = load_model(VERIFY_MODEL_PATH)
MODELS["disease"], MODELS["disease_classes"] = load_model(DISEASE_MODEL_PATH)
print("Models loaded successfully!")
test_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
@app.post("/analyze")
async def analyze_image(file: UploadFile = File(...)):
if MODELS["verify"] is None or MODELS["disease"] is None:
raise HTTPException(status_code=500, detail="Models not loaded")
try:
contents = await file.read()
if not contents:
raise ValueError("The server received an empty file (0 bytes). This is usually caused by a proxy stripping the file.")
try:
image = Image.open(io.BytesIO(contents)).convert('RGB')
except Exception as pil_err:
raise ValueError(f"Server received {len(contents)} bytes, but PIL failed to read it as an image. Details: {str(pil_err)}")
image_tensor = test_transform(image).unsqueeze(0).to(device)
except Exception as e:
print(f"FAILED TO LOAD IMAGE: {e}")
raise HTTPException(status_code=400, detail=str(e))
with torch.no_grad():
# First verify if it's a tomato leaf
v_out = MODELS["verify"](image_tensor)
v_probs = torch.softmax(v_out, dim=1).cpu().numpy()[0]
v_idx = v_probs.argmax()
is_tomato = MODELS["verify_classes"][v_idx] == "Tomatoes"
if not is_tomato:
return {
"success": True,
"is_tomato": False,
"confidence": float(v_probs[v_idx]),
"message": "This doesn't seem to be a tomato leaf. Please upload a clear image of a tomato leaf for best results.",
"suggestion": "Make sure the leaf fills most of the frame, is well-lit, and in focus."
}
# It's a tomato, check for diseases
d_out = MODELS["disease"](image_tensor)
d_probs = torch.softmax(d_out, dim=1).cpu().numpy()[0]
d_idx = d_probs.argmax()
disease_name = MODELS["disease_classes"][d_idx]
d_confidence = float(d_probs[d_idx])
# Prepare highly professional insights based on common disease labels
insights = {
"Late blight": (
"Overview: A highly destructive fungal disease (Phytophthora infestans) that thrives in cool, wet weather. "
"Symptoms: Dark, water-soaked spots on leaves that rapidly enlarge, white fungal growth on undersides.\n\n"
"🛡️ Treatment & Solutions:\n"
"• Immediate Action: Entirely remove and destroy infected plant parts immediately. Do not compost.\n"
"• Chemical Control: Apply fungicides containing chlorothalonil, copper fungicide, or mancozeb as scheduled sprays.\n"
"• Preventative Care: Maintain excellent air circulation; water at the base of the plant avoiding foliage; space plants properly."
),
"Early blight": (
"Overview: A common fungal disease (Alternaria solani) appearing on older foliage first.\n"
"Symptoms: Brown or black spots with characteristic concentric rings (target-board appearance) surrounded by yellow halos.\n\n"
"🛡️ Treatment & Solutions:\n"
"• Organic Control: Apply copper-based or sulfur-based fungicides organically approved. Neem oil can be used as a preventative measure.\n"
"• Chemical Control: Use chlorothalonil or azoxystrobin early in the infection cycle.\n"
"• Preventative Care: Crop rotation (3-4 years without nightshades), mulch to prevent soil splashing, and remove bottom leaves touching the soil."
),
"Bacterial spot": (
"Overview: Caused by Xanthomonas bacteria, severely impacting yield in warm, humid conditions.\n"
"Symptoms: Small, dark, water-soaked, scabby spots on fruit and leaves.\n\n"
"🛡️ Treatment & Solutions:\n"
"• Immediate Action: Bacteria are notoriously difficult to control once established. Remove infected crop debris post-harvest.\n"
"• Chemical Control: Preventative copper fungicide sprays combined with mancozeb can suppress the spread.\n"
"• Preventative Care: Use certified disease-free seeds/transplants; avoid working among wet plants to prevent spreading bacteria on hands and tools."
),
"Spider Mites": (
"Overview: Tiny arachnids that congregate on the undersides of leaves, thriving in hot, dry conditions.\n"
"Symptoms: Stippling (tiny yellow or white dots on leaves), fine webbing, and eventual leaf yellowing/dropping.\n\n"
"🛡️ Treatment & Solutions:\n"
"• Organic Control: Knock them off with a strong blast of water. Apply insecticidal soap, Neem oil, or introduce predatory mites (Phytoseiulus persimilis).\n"
"• Chemical Control: Use targeted miticides (abamectin or spiromesifen) if the infestation is severe.\n"
"• Preventative Care: Keep plants well-watered (stress increases susceptibility) and maintain higher localized humidity."
),
"Healthy": (
"Overview: Your tomato plant exhibits strong, vigorous growth with no current signs of widespread pathogens or pests.\n\n"
"🌱 Ongoing Best Practices:\n"
"• Nutrition: Ensure a balanced supply of Phosphorus and Potassium during fruiting.\n"
"• Watering: Maintain consistent soil moisture (avoiding wet-dry extremes to prevent blossom end rot).\n"
"• Maintenance: Continue pruning suckers for indeterminate varieties to maximize airflow and sunlight penetration."
)
}
suggestion = insights.get(disease_name, "Consult a local agricultural expert for treatment options tailored to your region.")
return {
"success": True,
"is_tomato": True,
"prediction": disease_name,
"confidence": d_confidence,
"suggestion": suggestion,
"all_probabilities": {str(cls): float(prob) for cls, prob in zip(MODELS["disease_classes"], d_probs)}
}
if __name__ == "__main__":
uvicorn.run("api:app", host="0.0.0.0", port=8000, reload=True)