Charuka66 commited on
Commit
b455adb
Β·
verified Β·
1 Parent(s): 334fadc

Upload 2 files

Browse files
Files changed (2) hide show
  1. best.pt +2 -2
  2. main.py +56 -78
best.pt CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:6a4a858112a248a4ac07bc254ccc70ca2f71048ed7b7e9018fe618ce766517cf
3
- size 54521258
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7f2e775168f7ce664b7abe08dbd5a7c903f5f3487c0711fe180fa8836015c312
3
+ size 77368442
main.py CHANGED
@@ -1,9 +1,7 @@
1
  from fastapi import FastAPI, File, UploadFile, Form
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from typing import List, Optional
4
- from sahi import AutoDetectionModel
5
- from sahi.predict import get_sliced_prediction
6
- from ultralytics import YOLO # πŸ‘ˆ Import YOLO for classification
7
  import uvicorn
8
  import shutil
9
  import os
@@ -19,80 +17,79 @@ app.add_middleware(
19
  )
20
 
21
  # ==========================================
22
- # 🧠 LOAD MODELS
23
  # ==========================================
24
  print("⏳ Loading Models...")
25
 
26
- # 1. Disease Detection Model (Your Custom Model)
27
  try:
28
- detection_model = AutoDetectionModel.from_pretrained(
29
- model_type='yolov8',
30
- model_path='best.pt',
31
- confidence_threshold=0.25,
32
- device='cpu'
33
- )
34
- print("βœ… Disease Model loaded!")
35
  except Exception as e:
36
  print(f"❌ Error loading Disease Model: {e}")
37
 
38
- # 2. Plant Gatekeeper Model (Generic Classifier)
39
- # This downloads automatically the first time (only ~6MB)
40
  try:
41
- classifier = YOLO('yolov8n-cls.pt')
 
42
  print("βœ… Plant Gatekeeper loaded!")
43
  except Exception as e:
44
  print(f"❌ Error loading Gatekeeper: {e}")
45
 
46
 
47
  # ==========================================
48
- # πŸ›‘οΈ THE IMPROVED PLANT GATEKEEPER
49
  # ==========================================
50
  def is_likely_plant(image_path):
51
  """
52
- Revised Logic: BLOCK specific non-plant objects (People, Electronics, Cars).
53
- ALLOW everything else (Nature, Fields, Valleys, etc.).
 
54
  """
55
  try:
56
- # Predict top class
57
- results = classifier(image_path, verbose=False)
58
- top_probs = results[0].probs.top1
59
- top_name = results[0].names[top_probs].lower()
60
 
61
- print(f"🧐 Gatekeeper sees: '{top_name}'")
62
-
63
- # β›” BLOCK LIST: If the AI sees these, REJECT the image.
64
- forbidden_keywords = [
65
- 'person', 'man', 'woman', 'boy', 'girl', 'human', 'face', 'groom', 'diver',
66
- 'computer', 'laptop', 'screen', 'monitor', 'keyboard', 'mouse', 'phone', 'cellular',
67
- 'car', 'vehicle', 'truck', 'bus', 'racer', 'motor', 'machine',
68
- 'furniture', 'table', 'chair', 'seat', 'couch', 'desk',
69
- 'dog', 'cat', 'animal', 'bear', 'lion'
 
 
70
  ]
71
 
72
- # Check if it matches a forbidden item
73
- for bad_word in forbidden_keywords:
74
- if bad_word in top_name:
75
- print(f"β›” Blocked: Detected '{top_name}' (Matched '{bad_word}')")
76
- return False
 
77
 
78
- # βœ… If it's not forbidden, we ALLOW it.
79
- # This lets "Valley", "Lakeside", "Grass", "Meadow" pass through.
80
- return True
81
 
82
  except Exception as e:
83
  print(f"⚠️ Gatekeeper Error: {e}")
84
- return True # If gatekeeper fails, let it pass to be safe
85
 
86
 
87
  def get_recommendation(disease_name):
88
  recommendations = {
89
- "Blast": "Use Tricyclazole 75 WP. Avoid excess nitrogen.",
90
- "Blight": "Drain field. Apply fresh water. Use bleaching powder.",
91
- "Brown Spot": "Improve soil fertility. Add Potassium.",
92
- "Hispa": "Spray Chloropyriphos. Clip leaf tips.",
93
- "Healthy": "Keep maintaining good water levels!"
94
  }
95
- return recommendations.get(disease_name, "Consult an agricultural officer.")
 
 
 
 
 
96
 
97
  @app.get("/")
98
  def home():
@@ -111,57 +108,38 @@ async def predict(
111
  with open(temp_filename, "wb") as buffer:
112
  shutil.copyfileobj(file.file, buffer)
113
 
114
- # πŸ›‘ STEP 1: RUN THE GATEKEEPER
115
  if not is_likely_plant(temp_filename):
116
- print("🚫 Rejected: Image does not look like a plant.")
117
  return {
118
  "filename": file.filename,
119
  "disease": "Invalid Image",
120
  "confidence": "0%",
121
- "recommendation": "This image does not appear to be a plant. Please upload a clear photo of your paddy field.",
122
  "latitude": float(latitude) if latitude else None,
123
  "longitude": float(longitude) if longitude else None
124
  }
125
 
126
- # βœ… STEP 2: RUN DISEASE DETECTION (SAHI)
127
- result = get_sliced_prediction(
128
- temp_filename,
129
- detection_model,
130
- slice_height=640,
131
- slice_width=640,
132
- overlap_height_ratio=0.2,
133
- overlap_width_ratio=0.2
134
- )
135
 
136
- predictions = result.object_prediction_list
 
 
 
137
 
138
  response_data = {
139
  "filename": file.filename,
 
 
 
140
  "latitude": float(latitude) if latitude else None,
141
  "longitude": float(longitude) if longitude else None
142
  }
143
 
144
- if len(predictions) > 0:
145
- best_pred = max(predictions, key=lambda x: x.score.value)
146
- detected_name = best_pred.category.name
147
- confidence_score = best_pred.score.value
148
-
149
- response_data.update({
150
- "disease": detected_name,
151
- "confidence": f"{int(confidence_score * 100)}%",
152
- "recommendation": get_recommendation(detected_name)
153
- })
154
- else:
155
- response_data.update({
156
- "disease": "Healthy / No Detection",
157
- "confidence": "0%",
158
- "recommendation": get_recommendation("Healthy")
159
- })
160
-
161
  return response_data
162
 
163
  except Exception as e:
164
- print(f"Error: {e}")
165
  return {"error": str(e)}
166
 
167
  finally:
 
1
  from fastapi import FastAPI, File, UploadFile, Form
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from typing import Optional
4
+ from ultralytics import YOLO
 
 
5
  import uvicorn
6
  import shutil
7
  import os
 
17
  )
18
 
19
  # ==========================================
20
+ # 🧠 LOAD MODELS (Classification Only!)
21
  # ==========================================
22
  print("⏳ Loading Models...")
23
 
 
24
  try:
25
+ # 1. Disease Classification Model (Your ultra-smart 96.8% brain)
26
+ disease_model = YOLO('best.pt')
27
+ print("βœ… Goyam Disease Classifier loaded!")
 
 
 
 
28
  except Exception as e:
29
  print(f"❌ Error loading Disease Model: {e}")
30
 
 
 
31
  try:
32
+ # 2. Plant Gatekeeper (ImageNet 1000-class classifier)
33
+ gatekeeper_model = YOLO('yolov8n-cls.pt')
34
  print("βœ… Plant Gatekeeper loaded!")
35
  except Exception as e:
36
  print(f"❌ Error loading Gatekeeper: {e}")
37
 
38
 
39
  # ==========================================
40
+ # πŸ›‘οΈ THE BULLETPROOF GATEKEEPER (Allowlist)
41
  # ==========================================
42
  def is_likely_plant(image_path):
43
  """
44
+ STRICT ALLOWLIST LOGIC:
45
+ We check the top 5 things the AI thinks it sees.
46
+ If NONE of them are related to nature, agriculture, or plants, we reject the photo.
47
  """
48
  try:
49
+ results = gatekeeper_model(image_path, verbose=False)
 
 
 
50
 
51
+ # Get the top 5 predicted classes
52
+ top5_indices = results[0].probs.top5
53
+ top5_names = [results[0].names[i].lower() for i in top5_indices]
54
+
55
+ print(f"🧐 Gatekeeper sees: {top5_names}")
56
+
57
+ # βœ… ALLOW LIST: Botanical, agricultural, and nature terms
58
+ allowed_keywords = [
59
+ 'plant', 'leaf', 'grass', 'flower', 'tree', 'fern', 'moss', 'weed',
60
+ 'crop', 'agriculture', 'field', 'greenhouse', 'pot', 'earth', 'soil',
61
+ 'vegetation', 'forest', 'valley', 'daisy', 'corn', 'acorn', 'paddy'
62
  ]
63
 
64
+ # Check if ANY of the top 5 predictions contain our allowed keywords
65
+ for predicted_item in top5_names:
66
+ for good_word in allowed_keywords:
67
+ if good_word in predicted_item:
68
+ print(f"βœ… Passed: Gatekeeper verified plant matter ('{predicted_item}')")
69
+ return True
70
 
71
+ # If the loop finishes and didn't find a single nature word, reject it!
72
+ print(f"🚫 Blocked: No agricultural or plant features detected.")
73
+ return False
74
 
75
  except Exception as e:
76
  print(f"⚠️ Gatekeeper Error: {e}")
77
+ return True # Fail-safe: let it pass if the gatekeeper crashes
78
 
79
 
80
  def get_recommendation(disease_name):
81
  recommendations = {
82
+ "Leaf Blast": "Use Tricyclazole 75 WP. Avoid applying excess nitrogen fertilizer.",
83
+ "Sheath Blight": "Drain the field immediately. Apply validamycin or carbendazim.",
84
+ "Brown Spot": "Improve soil fertility. Apply potassium and phosphorus.",
85
+ "Healthy Rice Leaf": "No disease detected. Keep maintaining optimal water levels!"
 
86
  }
87
+ # Fallback just in case class names differ slightly
88
+ for key, value in recommendations.items():
89
+ if key.lower() in disease_name.lower():
90
+ return value
91
+ return "Consult your local agricultural extension officer for treatment."
92
+
93
 
94
  @app.get("/")
95
  def home():
 
108
  with open(temp_filename, "wb") as buffer:
109
  shutil.copyfileobj(file.file, buffer)
110
 
111
+ # πŸ›‘ STEP 1: RUN THE STRICT GATEKEEPER
112
  if not is_likely_plant(temp_filename):
 
113
  return {
114
  "filename": file.filename,
115
  "disease": "Invalid Image",
116
  "confidence": "0%",
117
+ "recommendation": "This image does not appear to be a plant or paddy field. Please upload a clear photo of a rice leaf.",
118
  "latitude": float(latitude) if latitude else None,
119
  "longitude": float(longitude) if longitude else None
120
  }
121
 
122
+ # βœ… STEP 2: RUN DISEASE CLASSIFICATION
123
+ results = disease_model(temp_filename, verbose=False)
 
 
 
 
 
 
 
124
 
125
+ # Extract the highest probability prediction
126
+ top_idx = results[0].probs.top1
127
+ confidence_score = float(results[0].probs.top1conf)
128
+ detected_name = results[0].names[top_idx]
129
 
130
  response_data = {
131
  "filename": file.filename,
132
+ "disease": detected_name,
133
+ "confidence": f"{int(confidence_score * 100)}%",
134
+ "recommendation": get_recommendation(detected_name),
135
  "latitude": float(latitude) if latitude else None,
136
  "longitude": float(longitude) if longitude else None
137
  }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  return response_data
140
 
141
  except Exception as e:
142
+ print(f"❌ API Error: {e}")
143
  return {"error": str(e)}
144
 
145
  finally: