Spaces:
Sleeping
Sleeping
Green Doctor Deployer commited on
Commit ·
13bfee6
1
Parent(s): 3f7ebd7
Fix dictionary mapped strings for Specialist classes
Browse files- backend/app.py +6 -8
- test_hf_automated.py +82 -0
- test_specialist_local.py +55 -0
backend/app.py
CHANGED
|
@@ -193,18 +193,16 @@ SPECIALIST_MAP = {
|
|
| 193 |
"Corn (Maize) with Cercospora and Gray Leaf Spot": "Corn - Gray Leaf Spot",
|
| 194 |
"Corn (Maize) with Common Rust": "Corn - Common Rust",
|
| 195 |
"Corn (Maize) with Northern Leaf Blight": "Corn - Northern Leaf Blight",
|
| 196 |
-
"Healthy Corn": "Corn - Healthy",
|
| 197 |
-
"Grape with Black Measles": "Grape - Black Measles",
|
| 198 |
"Grape with Black Rot": "Grape - Black Rot",
|
| 199 |
-
"Grape with
|
| 200 |
-
"
|
|
|
|
| 201 |
"Orange with Citrus Greening": "Orange - Citrus Greening",
|
| 202 |
"Peach with Bacterial Spot": "Peach - Bacterial Spot",
|
| 203 |
-
"Healthy Peach": "Peach - Healthy",
|
| 204 |
-
"Pepper Bell with Bacterial Spot": "Pepper - Bacterial Spot",
|
| 205 |
"Bell Pepper with Bacterial Spot": "Pepper - Bacterial Spot",
|
| 206 |
-
"Healthy Pepper
|
| 207 |
-
"Healthy Bell Pepper": "Pepper - Healthy",
|
| 208 |
"Potato with Early Blight": "Potato - Early Blight",
|
| 209 |
"Potato with Late Blight": "Potato - Late Blight",
|
| 210 |
"Healthy Potato Plant": "Potato - Healthy",
|
|
|
|
| 193 |
"Corn (Maize) with Cercospora and Gray Leaf Spot": "Corn - Gray Leaf Spot",
|
| 194 |
"Corn (Maize) with Common Rust": "Corn - Common Rust",
|
| 195 |
"Corn (Maize) with Northern Leaf Blight": "Corn - Northern Leaf Blight",
|
| 196 |
+
"Healthy Corn (Maize) Plant": "Corn - Healthy",
|
|
|
|
| 197 |
"Grape with Black Rot": "Grape - Black Rot",
|
| 198 |
+
"Grape with Esca (Black Measles)": "Grape - Black Measles",
|
| 199 |
+
"Grape with Isariopsis Leaf Spot": "Grape - Leaf Blight",
|
| 200 |
+
"Healthy Grape Plant": "Grape - Healthy",
|
| 201 |
"Orange with Citrus Greening": "Orange - Citrus Greening",
|
| 202 |
"Peach with Bacterial Spot": "Peach - Bacterial Spot",
|
| 203 |
+
"Healthy Peach Plant": "Peach - Healthy",
|
|
|
|
| 204 |
"Bell Pepper with Bacterial Spot": "Pepper - Bacterial Spot",
|
| 205 |
+
"Healthy Bell Pepper Plant": "Pepper - Healthy",
|
|
|
|
| 206 |
"Potato with Early Blight": "Potato - Early Blight",
|
| 207 |
"Potato with Late Blight": "Potato - Late Blight",
|
| 208 |
"Healthy Potato Plant": "Potato - Healthy",
|
test_hf_automated.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
import io
|
| 3 |
+
import time
|
| 4 |
+
import urllib.request
|
| 5 |
+
import json
|
| 6 |
+
from PIL import Image
|
| 7 |
+
|
| 8 |
+
API_URL = "https://rhamprassath-greendoctor-backend.hf.space/predict"
|
| 9 |
+
|
| 10 |
+
# Known URLs of raw PlantVillage images from a public repo
|
| 11 |
+
TEST_IMAGES = {
|
| 12 |
+
# Specialist Examples
|
| 13 |
+
"Tomato - Septoria": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Tomato___Septoria_leaf_spot/0a555f63-bf03-4958-8993-e1932b8dce9f___JR_Sept.L.S%208395.JPG",
|
| 14 |
+
"Tomato - Early Blight": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Tomato___Early_blight/0a0a5247-c035-42a9-aa5a-b6e828453ad2___RS_Erly.B%209425.JPG",
|
| 15 |
+
"Potato - Late Blight": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Potato___Late_blight/0a1a084c-ddbe-4767-a06f-13589be76228___RS_LB%202758.JPG",
|
| 16 |
+
"Apple - Scab": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Apple___Apple_scab/0a5e9323-dbad-432d-ac58-d291718345d9___FREC_Scab%203417.JPG",
|
| 17 |
+
"Corn - Common Rust": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Corn_(maize)___Common_rust_/RS_Rust%201676.JPG",
|
| 18 |
+
"Grape - Black Rot": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Grape___Black_rot/0a283e58-f9b6-4993-bc89-10659345712c___FAM_B.Rot%200585.JPG",
|
| 19 |
+
"Peach - Bacterial Spot": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Peach___Bacterial_spot/0a158b43-2df7-463d-bacc-39bf7238a204___Rutg._Bact.S%201402.JPG",
|
| 20 |
+
|
| 21 |
+
# Healthy Varieties
|
| 22 |
+
"Tomato - Healthy": "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Tomato___healthy/0a0bb533-5c74-4286-90ae-2fba6b364429___GH_Hlthy%209689.JPG",
|
| 23 |
+
|
| 24 |
+
# We also have Generalist classes like Rice and Wheat, but those aren't in PlantVillage exactly,
|
| 25 |
+
# so we will use a couple of generic links for them if needed.
|
| 26 |
+
"Rice - Leaf Blast": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Magnaporthe_grisea.jpg",
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
def verify_all_plants():
|
| 30 |
+
print("Downloading & Testing PlantVillage Images against HuggingFace Engine...")
|
| 31 |
+
print("API Endpoint:", API_URL)
|
| 32 |
+
print("-" * 60)
|
| 33 |
+
|
| 34 |
+
results = []
|
| 35 |
+
|
| 36 |
+
for name, url in TEST_IMAGES.items():
|
| 37 |
+
try:
|
| 38 |
+
print(f"Downloading {name}...")
|
| 39 |
+
# We use urllib to handle spaces in URLs properly if any
|
| 40 |
+
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
|
| 41 |
+
with urllib.request.urlopen(req) as response:
|
| 42 |
+
img_data = response.read()
|
| 43 |
+
|
| 44 |
+
# Post to HuggingFace
|
| 45 |
+
print(f"Testing {name} on HuggingFace Space...")
|
| 46 |
+
files = {'file': (f'{name.replace(" ", "_")}.jpg', img_data, 'image/jpeg')}
|
| 47 |
+
|
| 48 |
+
# Record time for performance metrics
|
| 49 |
+
start_time = time.time()
|
| 50 |
+
resp = requests.post(API_URL, files=files, timeout=40)
|
| 51 |
+
elapsed = time.time() - start_time
|
| 52 |
+
|
| 53 |
+
if resp.status_code == 200:
|
| 54 |
+
result = resp.json()
|
| 55 |
+
status_icon = "PASS" if result.get('class') != "UNKNOWN" else "WARN"
|
| 56 |
+
print(f"{status_icon} RESULT for {name} ({elapsed:.1f}s):")
|
| 57 |
+
print(f" ► Class Predicted: {result.get('class')}")
|
| 58 |
+
print(f" ► Confidence: {result.get('confidence', 0)*100:.1f}%")
|
| 59 |
+
print(f" ► AI Details: {result.get('ai_details')}")
|
| 60 |
+
|
| 61 |
+
results.append({
|
| 62 |
+
"Target": name,
|
| 63 |
+
"Predicted": result.get('class'),
|
| 64 |
+
"Confidence": f"{result.get('confidence', 0)*100:.1f}%",
|
| 65 |
+
"Expert": result.get('ai_details')
|
| 66 |
+
})
|
| 67 |
+
|
| 68 |
+
else:
|
| 69 |
+
print(f"FAILED for {name}: {resp.status_code} - {resp.text}")
|
| 70 |
+
|
| 71 |
+
except Exception as e:
|
| 72 |
+
print(f"Error testing {name} (Link might be dead): {e}")
|
| 73 |
+
print("-" * 60)
|
| 74 |
+
time.sleep(1) # Prevent rate limiting
|
| 75 |
+
|
| 76 |
+
print("\n\n SUMMARY REPORT:")
|
| 77 |
+
for r in results:
|
| 78 |
+
match = "MATCH" if r['Predicted'].lower().split('-')[0].strip() in r['Target'].lower() else "CONFLICT"
|
| 79 |
+
print(f"Target: {r['Target']:<25} | Predicted: {r['Predicted']:<25} | {r['Confidence']} | {match}")
|
| 80 |
+
|
| 81 |
+
if __name__ == "__main__":
|
| 82 |
+
verify_all_plants()
|
test_specialist_local.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import AutoModelForImageClassification
|
| 2 |
+
import torch
|
| 3 |
+
import numpy as np
|
| 4 |
+
from PIL import Image
|
| 5 |
+
import requests
|
| 6 |
+
import io
|
| 7 |
+
import urllib.request
|
| 8 |
+
|
| 9 |
+
def test_local():
|
| 10 |
+
print("Loading MobileNetV2 locally...")
|
| 11 |
+
model_name = "linkanjarad/mobilenet_v2_1.0_224-plant-disease-identification"
|
| 12 |
+
model = AutoModelForImageClassification.from_pretrained(model_name).to(torch.float32)
|
| 13 |
+
model.eval()
|
| 14 |
+
|
| 15 |
+
print("Fetching sample Tomato Septoria image...")
|
| 16 |
+
url = "https://raw.githubusercontent.com/spMohanty/PlantVillage-Dataset/master/raw/color/Tomato___Septoria_leaf_spot/0a555f63-bf03-4958-8993-e1932b8dce9f___JR_Sept.L.S%208395.JPG"
|
| 17 |
+
|
| 18 |
+
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
|
| 19 |
+
try:
|
| 20 |
+
with urllib.request.urlopen(req) as response:
|
| 21 |
+
img_data = response.read()
|
| 22 |
+
image = Image.open(io.BytesIO(img_data)).convert("RGB").resize((224, 224))
|
| 23 |
+
except Exception as e:
|
| 24 |
+
print("Could not download image. Creating a synthetic green image with black spots...")
|
| 25 |
+
image = Image.new('RGB', (224, 224), color=(30, 150, 30))
|
| 26 |
+
# draw spots
|
| 27 |
+
for _ in range(100):
|
| 28 |
+
x, y = np.random.randint(0, 224, 2)
|
| 29 |
+
for i in range(3):
|
| 30 |
+
for j in range(3):
|
| 31 |
+
if x+i<224 and y+j<224:
|
| 32 |
+
image.putpixel((x+i, y+j), (50, 20, 0))
|
| 33 |
+
|
| 34 |
+
img_array = np.array(image).astype(np.float32) / 255.0
|
| 35 |
+
mean = np.array([0.5, 0.5, 0.5])
|
| 36 |
+
std = np.array([0.5, 0.5, 0.5])
|
| 37 |
+
img_array = (img_array - mean) / std
|
| 38 |
+
img_array = img_array.transpose(2, 0, 1)
|
| 39 |
+
inputs = torch.tensor(img_array, dtype=torch.float32).unsqueeze(0)
|
| 40 |
+
|
| 41 |
+
with torch.no_grad():
|
| 42 |
+
outputs = model(inputs)
|
| 43 |
+
|
| 44 |
+
probs = torch.nn.functional.softmax(outputs.logits, dim=-1)[0]
|
| 45 |
+
|
| 46 |
+
print("\n--- TOP 3 PREDICTIONS ---")
|
| 47 |
+
top3 = torch.topk(probs, 3)
|
| 48 |
+
for i in range(3):
|
| 49 |
+
idx = top3.indices[i].item()
|
| 50 |
+
score = top3.values[i].item()
|
| 51 |
+
label = model.config.id2label[idx]
|
| 52 |
+
print(f"{i+1}. {label} : {score*100:.2f}%")
|
| 53 |
+
|
| 54 |
+
if __name__ == "__main__":
|
| 55 |
+
test_local()
|