Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, File, UploadFile, Form | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from typing import Optional | |
| from ultralytics import YOLO | |
| import uvicorn | |
| import shutil | |
| import os | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ========================================== | |
| # LOAD MODELS (Dual-Architecture) | |
| # ========================================== | |
| print("β³ Loading Models...") | |
| try: | |
| disease_model = YOLO('best.pt') | |
| print("β Goyam Disease Classifier loaded!") | |
| except Exception as e: | |
| print(f"β Error loading Disease Model: {e}") | |
| try: | |
| gatekeeper_model = YOLO('yolov8n-cls.pt') | |
| print("β Plant Gatekeeper loaded!") | |
| except Exception as e: | |
| print(f"β Error loading Gatekeeper: {e}") | |
| # ========================================== | |
| # π‘οΈ THE SMART GATEKEEPER | |
| # ========================================== | |
| def is_likely_plant(image_path): | |
| try: | |
| results = gatekeeper_model(image_path, verbose=False) | |
| top5_indices = results[0].probs.top5 | |
| top5_names = [results[0].names[i].lower() for i in top5_indices] | |
| print(f"Gatekeeper sees: {top5_names}") | |
| # ALLOW LIST: Botanical terms AND known macro-photography hallucinations | |
| allowed_keywords = [ | |
| # True Botanical | |
| 'plant', 'leaf', 'grass', 'flower', 'tree', 'fern', 'moss', 'weed', | |
| 'crop', 'agriculture', 'field', 'greenhouse', 'pot', 'earth', 'soil', | |
| 'vegetation', 'forest', 'valley', 'daisy', 'corn', 'acorn', 'paddy', 'cardoon', 'reed', | |
| # Common ImageNet Hallucinations for extreme close-up leaf textures | |
| 'damselfly', 'chameleon', 'lizard', 'ear', 'lacewing', 'spider', 'insect', | |
| 'bug', 'mantis', 'paintbrush', 'broom', 'bow', 'nematode', 'slug', 'snail', 'snake' | |
| ] | |
| for predicted_item in top5_names: | |
| for good_word in allowed_keywords: | |
| if good_word in predicted_item: | |
| print(f"β Passed: Gatekeeper authorized based on '{predicted_item}'") | |
| return True | |
| print(f" Blocked: No natural or agricultural features detected.") | |
| return False | |
| except Exception as e: | |
| print(f" Gatekeeper Error: {e}") | |
| return True | |
| def get_recommendation(disease_name): | |
| recommendations = { | |
| "Leaf Blast": "Use Tricyclazole 75 WP. Avoid applying excess nitrogen fertilizer.", | |
| "Sheath Blight": "Drain the field immediately. Apply validamycin or carbendazim.", | |
| "Brown Spot": "Improve soil fertility. Apply potassium and phosphorus.", | |
| "Healthy Rice Leaf": "No disease detected. Keep maintaining optimal water levels!" | |
| } | |
| for key, value in recommendations.items(): | |
| if key.lower() in disease_name.lower(): | |
| return value | |
| return "Consult your local agricultural extension officer for treatment." | |
| async def predict( | |
| file: UploadFile = File(...), | |
| latitude: Optional[str] = Form(None), | |
| longitude: Optional[str] = Form(None) | |
| ): | |
| print(f" Receiving image: {file.filename}") | |
| temp_filename = f"temp_{file.filename}" | |
| try: | |
| with open(temp_filename, "wb") as buffer: | |
| shutil.copyfileobj(file.file, buffer) | |
| # π STEP 1: RUN THE SMART GATEKEEPER | |
| if not is_likely_plant(temp_filename): | |
| return { | |
| "filename": file.filename, | |
| "disease": "Invalid Image", | |
| "confidence": "0%", | |
| "recommendation": "This image does not appear to be a plant or paddy field. Please upload a clear photo of a rice leaf.", | |
| "latitude": float(latitude) if latitude else None, | |
| "longitude": float(longitude) if longitude else None | |
| } | |
| # STEP 2: RUN DISEASE CLASSIFICATION | |
| results = disease_model(temp_filename, verbose=False) | |
| top_idx = results[0].probs.top1 | |
| confidence_score = float(results[0].probs.top1conf) | |
| detected_name = results[0].names[top_idx] | |
| response_data = { | |
| "filename": file.filename, | |
| "disease": detected_name, | |
| "confidence": f"{int(confidence_score * 100)}%", | |
| "recommendation": get_recommendation(detected_name), | |
| "latitude": float(latitude) if latitude else None, | |
| "longitude": float(longitude) if longitude else None | |
| } | |
| return response_data | |
| except Exception as e: | |
| print(f" API Error: {e}") | |
| return {"error": str(e)} | |
| finally: | |
| if os.path.exists(temp_filename): | |
| os.remove(temp_filename) | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=7860) |