File size: 4,845 Bytes
01efda8
c4a6183
b455adb
 
c4a6183
 
 
 
 
 
 
 
 
 
 
 
 
 
f6f1d5f
3a67dd1
f6f1d5f
 
 
c4a6183
b455adb
3a67dd1
f6f1d5f
3a67dd1
 
 
 
 
 
 
f6f1d5f
 
 
3a67dd1
f6f1d5f
3a67dd1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b00dada
 
b455adb
 
 
 
b00dada
b455adb
 
 
 
 
c4a6183
01efda8
 
f6f1d5f
 
01efda8
3a67dd1
c4a6183
b00dada
c4a6183
b00dada
01efda8
b00dada
3a67dd1
 
7994462
 
 
3a67dd1
 
7994462
 
 
 
3a67dd1
 
 
 
 
 
 
b00dada
 
b455adb
 
 
01efda8
 
b00dada
 
 
c4a6183
 
7994462
c4a6183
 
 
 
 
 
 
ccd2742
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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."

@app.post("/predict")
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)