nomandiu9 commited on
Commit
8deeb06
·
1 Parent(s): 028141c

Rollback to stable v6.1: 2026-01-27 00:54:34

Browse files
Files changed (2) hide show
  1. app.py +71 -51
  2. requirements.txt +1 -2
app.py CHANGED
@@ -5,7 +5,6 @@ from ultralytics import YOLO
5
  from PIL import Image, ImageOps
6
  import io
7
  import tensorflow as tf
8
- import keras
9
  import numpy as np
10
  from tensorflow.keras.applications.mobilenet_v3 import preprocess_input
11
  import os
@@ -17,7 +16,7 @@ HF_TOKEN = os.environ.get("HF_TOKEN")
17
 
18
  app = FastAPI()
19
 
20
- # 2. CORS Setup
21
  app.add_middleware(
22
  CORSMiddleware,
23
  allow_origins=["*"],
@@ -26,59 +25,73 @@ app.add_middleware(
26
  allow_headers=["*"],
27
  )
28
 
29
- # 3. Model Constants
30
  CLASS_NAMES = ['Anthracnose', 'Cercospora', 'Fresh Leaf', 'Leaf Curl']
31
- YOLO_MODEL_PATH = "best.pt"
32
- MOBILENET_MODEL_PATH = "mobilenetv3_chili_leaf_global.keras"
33
 
 
34
  yolo_model = None
35
  mobilenet_model = None
36
 
37
- # 4. Model Loading Functions
38
- def load_models():
39
- global yolo_model, mobilenet_model
40
-
41
- # --- Load YOLO ---
42
  try:
43
- print(f"Attempting to load YOLO from {YOLO_MODEL_PATH}...")
44
- target_path = YOLO_MODEL_PATH
45
- if not os.path.exists(target_path):
46
- from huggingface_hub import hf_hub_download
47
- print("Downloading YOLO from HF Hub...")
48
- target_path = hf_hub_download(repo_id="nomandiu9/chili", filename=YOLO_MODEL_PATH, token=HF_TOKEN)
49
- yolo_model = YOLO(target_path)
50
- print("YOLO model loaded successfully.")
 
 
 
 
 
 
51
  except Exception as e:
52
- print(f"ERROR loading YOLO: {e}")
53
 
54
- # --- Load MobileNet ---
 
 
55
  try:
56
- print(f"Attempting to load MobileNet from {MOBILENET_MODEL_PATH}...")
57
- target_path = MOBILENET_MODEL_PATH
58
- if not os.path.exists(target_path):
 
 
 
 
 
 
 
 
59
  from huggingface_hub import hf_hub_download
60
  print("Downloading MobileNet from HF Hub...")
61
- target_path = hf_hub_download(repo_id="nomandiu9/chili", filename=MOBILENET_MODEL_PATH, token=HF_TOKEN)
62
 
63
- # Use keras 3 standalone for .keras files
64
  try:
 
 
65
  mobilenet_model = keras.models.load_model(target_path, compile=False)
66
- print("MobileNet whole model loaded successfully.")
67
- except Exception as e1:
68
- print(f"Full model load failed ({e1}), trying weights-only...")
69
- try:
70
- mobilenet_model = tf.keras.applications.MobileNetV3Large(weights=None, classes=len(CLASS_NAMES))
71
- mobilenet_model.load_weights(target_path)
72
- print("MobileNet weights loaded successfully.")
73
- except Exception as e2:
74
- print(f"CRITICAL ERROR loading MobileNet: {e2}")
75
  except Exception as e:
76
- print(f"ERROR loading MobileNet: {e}")
77
 
78
- # Initial Trigger (DIRECT)
79
- load_models()
 
80
 
81
- # 5. API Endpoints
82
  @app.get("/")
83
  def read_root():
84
  return {
@@ -90,35 +103,40 @@ def read_root():
90
  @app.post("/predict")
91
  async def predict(image: UploadFile = File(...)):
92
  if not yolo_model or not mobilenet_model:
93
- raise HTTPException(status_code=503, detail="Models are initializing")
94
 
95
- # Read and orient image
96
  image_bytes = await image.read()
97
  img = Image.open(io.BytesIO(image_bytes))
98
  img = ImageOps.exif_transpose(img).convert("RGB")
99
 
100
  results_data = {}
101
 
102
- # --- Step 1: YOLO Bounding Boxes ---
103
  try:
104
- yolo_results = yolo_model(img, imgsz=640, conf=0.15, verbose=False)
105
  yolo_res = yolo_results[0]
106
  boxes = []
107
  if hasattr(yolo_res, 'boxes') and yolo_res.boxes is not None:
108
  for box in yolo_res.boxes:
109
- coords = box.xyxy[0].tolist()
 
 
110
  boxes.append({
 
111
  "bbox": coords,
112
- "confidence": float(box.conf.item()) * 100
 
113
  })
114
  results_data["yolo"] = {"boxes": boxes}
115
  except Exception as e:
116
- results_data["yolo"] = {"boxes": [], "error": str(e)}
 
117
 
118
- # --- Step 2: MobileNet Identification ---
119
  try:
120
- # Resize to 224x224 for MobileNet
121
- img_resized = img.resize((224, 224), Image.NEAREST)
122
  img_array = np.asarray(img_resized, dtype=np.float32)
123
  img_array = np.expand_dims(img_array, axis=0)
124
  img_array = preprocess_input(img_array)
@@ -135,12 +153,14 @@ async def predict(image: UploadFile = File(...)):
135
  "confidence": confidence
136
  }
137
 
138
- # --- Step 3: Label Sync ---
139
- # Sync all YOLO boxes to use the MobileNet label
140
  for box in results_data["yolo"]["boxes"]:
141
  box["label"] = predicted_class
142
-
 
143
  except Exception as e:
 
144
  results_data["mobilenet"] = {"error": str(e)}
145
 
146
  return results_data
 
5
  from PIL import Image, ImageOps
6
  import io
7
  import tensorflow as tf
 
8
  import numpy as np
9
  from tensorflow.keras.applications.mobilenet_v3 import preprocess_input
10
  import os
 
16
 
17
  app = FastAPI()
18
 
19
+ # Enable CORS for frontend access
20
  app.add_middleware(
21
  CORSMiddleware,
22
  allow_origins=["*"],
 
25
  allow_headers=["*"],
26
  )
27
 
28
+ # Constants
29
  CLASS_NAMES = ['Anthracnose', 'Cercospora', 'Fresh Leaf', 'Leaf Curl']
30
+ YOLO_MODEL_NAME = "best.pt"
31
+ MOBILENET_MODEL_NAME = "mobilenetv3_chili_leaf_global.keras"
32
 
33
+ # Global model variables
34
  yolo_model = None
35
  mobilenet_model = None
36
 
37
+ def load_yolo():
38
+ global yolo_model
39
+ print(f"Loading YOLO model: {YOLO_MODEL_NAME}")
 
 
40
  try:
41
+ # Check local paths first
42
+ paths = [YOLO_MODEL_NAME, f"backend/{YOLO_MODEL_NAME}", f"/app/{YOLO_MODEL_NAME}"]
43
+ for p in paths:
44
+ if os.path.exists(p):
45
+ yolo_model = YOLO(p)
46
+ print(f"YOLO loaded from: {p}")
47
+ return
48
+
49
+ # Fallback to HF Hub
50
+ from huggingface_hub import hf_hub_download
51
+ print("Downloading YOLO from HF Hub...")
52
+ hf_path = hf_hub_download(repo_id="nomandiu9/chili", filename=YOLO_MODEL_NAME, token=HF_TOKEN)
53
+ yolo_model = YOLO(hf_path)
54
+ print("YOLO loaded from HF Hub")
55
  except Exception as e:
56
+ print(f"FAILED to load YOLO: {e}")
57
 
58
+ def load_mobilenet():
59
+ global mobilenet_model
60
+ print(f"Loading MobileNet model: {MOBILENET_MODEL_NAME}")
61
  try:
62
+ # Check local paths
63
+ target_path = None
64
+ paths = [MOBILENET_MODEL_NAME, f"backend/{MOBILENET_MODEL_NAME}", f"/app/{MOBILENET_MODEL_NAME}"]
65
+ for p in paths:
66
+ if os.path.exists(p):
67
+ target_path = p
68
+ print(f"Found MobileNet at: {p}")
69
+ break
70
+
71
+ # Fallback to HF Hub
72
+ if not target_path:
73
  from huggingface_hub import hf_hub_download
74
  print("Downloading MobileNet from HF Hub...")
75
+ target_path = hf_hub_download(repo_id="nomandiu9/chili", filename=MOBILENET_MODEL_NAME, token=HF_TOKEN)
76
 
77
+ # Load the model
78
  try:
79
+ # Try keras 3 standalone first
80
+ import keras
81
  mobilenet_model = keras.models.load_model(target_path, compile=False)
82
+ print("MobileNet whole model loaded.")
83
+ except:
84
+ print("Full model load failed, trying weights-only...")
85
+ mobilenet_model = tf.keras.applications.MobileNetV3Large(weights=None, classes=len(CLASS_NAMES))
86
+ mobilenet_model.load_weights(target_path)
87
+ print("MobileNet weights loaded.")
 
 
 
88
  except Exception as e:
89
+ print(f"FAILED to load MobileNet: {e}")
90
 
91
+ # Initial load
92
+ load_yolo()
93
+ load_mobilenet()
94
 
 
95
  @app.get("/")
96
  def read_root():
97
  return {
 
103
  @app.post("/predict")
104
  async def predict(image: UploadFile = File(...)):
105
  if not yolo_model or not mobilenet_model:
106
+ return {"error": "Models are still initializing. Try again in a few seconds."}
107
 
108
+ # 1. Read and fix image orientation
109
  image_bytes = await image.read()
110
  img = Image.open(io.BytesIO(image_bytes))
111
  img = ImageOps.exif_transpose(img).convert("RGB")
112
 
113
  results_data = {}
114
 
115
+ # 2. YOLO Bounding Box Extraction
116
  try:
117
+ yolo_results = yolo_model(img, imgsz=640, conf=0.15, verbose=False)
118
  yolo_res = yolo_results[0]
119
  boxes = []
120
  if hasattr(yolo_res, 'boxes') and yolo_res.boxes is not None:
121
  for box in yolo_res.boxes:
122
+ coords = box.xyxy[0].tolist() # [x1, y1, x2, y2]
123
+ conf = float(box.conf.item()) * 100
124
+ cls_id = int(box.cls.item())
125
  boxes.append({
126
+ "id": cls_id,
127
  "bbox": coords,
128
+ "yolo_label": yolo_res.names[cls_id],
129
+ "yolo_confidence": conf
130
  })
131
  results_data["yolo"] = {"boxes": boxes}
132
  except Exception as e:
133
+ print(f"YOLO inference error: {e}")
134
+ results_data["yolo"] = {"error": str(e), "boxes": []}
135
 
136
+ # 3. MobileNet Disease Detection
137
  try:
138
+ # Preprocessing
139
+ img_resized = img.resize((224, 224), Image.NEAREST)
140
  img_array = np.asarray(img_resized, dtype=np.float32)
141
  img_array = np.expand_dims(img_array, axis=0)
142
  img_array = preprocess_input(img_array)
 
153
  "confidence": confidence
154
  }
155
 
156
+ # 4. Integrate YOLO boxes with MobileNet labels
157
+ # We use YOLO for WHERE the disease is, but MobileNet for WHAT the disease is.
158
  for box in results_data["yolo"]["boxes"]:
159
  box["label"] = predicted_class
160
+ box["confidence"] = confidence # Use MobileNet's confidence for the final label
161
+
162
  except Exception as e:
163
+ print(f"MobileNet inference error: {e}")
164
  results_data["mobilenet"] = {"error": str(e)}
165
 
166
  return results_data
requirements.txt CHANGED
@@ -4,5 +4,4 @@ python-multipart
4
  ultralytics
5
  pillow
6
  huggingface-hub
7
- tensorflow>=2.16.1
8
- keras>=3.0.0
 
4
  ultralytics
5
  pillow
6
  huggingface-hub
7
+ tensorflow-cpu