dzmu commited on
Commit
813214c
·
verified ·
1 Parent(s): 9c1e7e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -70
app.py CHANGED
@@ -5,15 +5,13 @@ import numpy as np
5
  import random
6
  import os
7
  from PIL import Image
8
- from ultralytics import YOLO # Needed for both person and fashion detection
9
  from gtts import gTTS
10
  import uuid
11
  import time
12
  import tempfile
13
  from huggingface_hub import hf_hub_download
14
- #from src.backend import analyze_outfit
15
- #test
16
- # --- Configuration ---
17
  HF_TOKEN = os.environ.get("HF_TOKEN")
18
 
19
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
@@ -33,11 +31,11 @@ YOLO_FASHION_MODEL_PATH = hf_hub_download(
33
  CLIP_MODEL_NAME = "ViT-B/32"
34
 
35
  # Confidence Thresholds
36
- YOLO_PERSON_CONF_THRESHOLD = 0.4 # Min confidence for detecting a person
37
- YOLO_FASHION_CONF_THRESHOLD = 0.4 # Min confidence for detecting a fashion item
38
- YOLO_FASHION_HIGH_CONF_THRESHOLD = 0.6 # Higher threshold to prioritize fashion model item
 
39
 
40
- # --- Define Fashion Model Classes (IMPORTANT: Match these to your 'best.pt' training) ---
41
  FASHION_CLASSES = {
42
  0: 'long sleeve top', 1: 'skirt', 2: 'trousers', 3: 'short sleeve top',
43
  4: 'long sleeve outwear', 5: 'short sleeve dress', 6: 'shorts',
@@ -46,30 +44,27 @@ FASHION_CLASSES = {
46
  }
47
  print(f"Defined {len(FASHION_CLASSES)} fashion categories for {YOLO_FASHION_MODEL_PATH}")
48
 
49
- # --- Load Models ---
50
  print(f"Using device: {DEVICE}")
51
  try:
52
  clip_model, clip_preprocess = clip.load(CLIP_MODEL_NAME, device=DEVICE)
53
  print(f"CLIP model ({CLIP_MODEL_NAME}) loaded successfully.")
54
  except Exception as e:
55
  print(f"Error loading CLIP model: {e}")
56
- # Handle error or exit if critical
57
 
58
  try:
59
- yolo_person_model = YOLO(YOLO_PERSON_MODEL_PATH) # No .to(DEVICE) needed here for Ultralytics YOLO v8
60
  print(f"YOLO person detection model ({YOLO_PERSON_MODEL_PATH}) loaded successfully.")
61
  except Exception as e:
62
  print(f"Error loading YOLO person model: {e}")
63
- # Handle error or exit if critical
64
 
65
  try:
66
  yolo_fashion_model = YOLO(YOLO_FASHION_MODEL_PATH) # No .to(DEVICE) needed here
67
  print(f"YOLO fashion detection model ({YOLO_FASHION_MODEL_PATH}) loaded successfully.")
68
  except Exception as e:
69
  print(f"Error loading YOLO fashion model: {e}")
70
- # Handle error or exit if critical - The app might still work with CLIP only
71
 
72
- # --- Prompts and Responses ---
73
  style_prompts = {
74
  'drippy': [
75
  "avant-garde streetwear", "high-fashion designer outfit", "trendsetting urban attire",
@@ -85,7 +80,7 @@ style_prompts = {
85
  ]
86
  }
87
 
88
- # Clothing prompts for CLIP (still useful as fallback and general context)
89
  clothing_prompts = [
90
  "t-shirt", "dress shirt", "blouse", "hoodie", "jacket", "sweater", "coat",
91
  "dress", "skirt", "pants", "jeans", "trousers", "shorts",
@@ -93,15 +88,15 @@ clothing_prompts = [
93
  "cap", "hat", "scarf", "gloves", "bag", "accessory", "tank-top", "haircut"
94
  ]
95
 
96
- # Combine all prompts for CLIP
97
  all_prompts = []
98
  for cat_prompts in style_prompts.values():
99
  all_prompts.extend(cat_prompts)
100
- style_prompts_end_index = len(all_prompts) # Mark where style prompts end dont mess up loop
101
  all_prompts.extend(clothing_prompts)
102
- #print(f"Total prompts for CLIP: {len(all_prompts)}")
103
 
104
- # Response Templates maybe not call out specific item all the time?
 
105
  response_templates = {
106
  'drippy': [
107
  "You're Drippy, bruh – fire {item}!",
@@ -140,24 +135,24 @@ def format_detected_items(item_list):
140
  return ""
141
  return "<p class='result-items'>Detected items: " + ", ".join(item_list) + "</p>"
142
 
143
- # --- Helper Functions ---
144
  def get_top_clip_clothing(probs, n=1):
145
  """Gets the top N clothing items based on CLIP probabilities."""
146
  clothing_probs_start_index = style_prompts_end_index
147
  clothing_probs = probs[clothing_probs_start_index:]
148
  actual_n = min(n, len(clothing_prompts))
149
  if actual_n <= 0:
150
- return [] # Return empty list if no clothing prompts
 
151
 
152
- # Get indices and probabilities of top N items within the clothing slice
153
  top_indices_in_slice = np.argsort(clothing_probs)[-actual_n:]
154
- # Convert back to indices in the original all_probs array
155
  top_global_indices = [idx + clothing_probs_start_index for idx in top_indices_in_slice]
156
 
157
- # Return list of tuples: (item_name, probability)
158
  top_items_with_probs = [
159
  (clothing_prompts[i], clothing_probs[i])
160
- for i in reversed(top_indices_in_slice) # Get highest prob first
161
  ]
162
  return top_items_with_probs
163
  def wrapped_analyze(input_img):
@@ -178,7 +173,7 @@ def wrapped_analyze(input_img):
178
  DEVICE
179
  )
180
  def analyze_outfit(input_img):
181
- # Handle both file paths and PIL Images
182
  if isinstance(input_img, str):
183
  try:
184
  input_img = Image.open(input_img)
@@ -186,38 +181,32 @@ def analyze_outfit(input_img):
186
  return (f"<p style='color: #FF5555;'>Error loading image: {str(e)}</p>",
187
  None, "Image loading error")
188
 
189
- # Existing code continues...
190
  if input_img is None:
191
  return ("<p style='color: #FF5555; text-align: center;'>Please upload an image.</p>",
192
  None, "Error: No image provided.")
193
 
194
  img = input_img.convert("RGB").copy()
195
- #def analyze_outfit(image):
196
- #if image is None:
197
- #return ("<p style='color: #FF5555; text-align: center;'>Please upload an image.</p>", None, "Error: No image provided.")
198
- #image = image.convert("RGB").copy()
199
- #print(f"[DEBUG] image_path type: {type(image_path)} | value: {image_path}")
200
 
201
- # 1) YOLO Person Detection
202
  person_results = yolo_person_model(img, verbose=False, conf=YOLO_PERSON_CONF_THRESHOLD)
203
  boxes = person_results[0].boxes.xyxy.cpu().numpy()
204
  classes = person_results[0].boxes.cls.cpu().numpy()
205
  confidences = person_results[0].boxes.conf.cpu().numpy()
206
 
207
- # Filter for persons (class 0 in standard YOLOv8)
208
  person_indices = np.where(classes == 0)[0]
209
- cropped_img = img # Default to full image if no person found
210
  person_detected = False
211
 
212
  if len(person_indices) > 0:
213
- # Find the person detection with the highest confidence
214
  max_conf_person_idx = person_indices[np.argmax(confidences[person_indices])]
215
  x1, y1, x2, y2 = map(int, boxes[max_conf_person_idx])
216
- # Ensure coordinates are valid and within image bounds
217
  x1, y1 = max(0, x1), max(0, y1)
218
  x2, y2 = min(img.width, x2), min(img.height, y2)
219
 
220
- if x1 < x2 and y1 < y2: # Check if the box has valid dimensions
221
  cropped_img = img.crop((x1, y1, x2, y2))
222
  print(f"Person detected and cropped: Box {x1, y1, x2, y2}")
223
  person_detected = True
@@ -227,10 +216,10 @@ def analyze_outfit(input_img):
227
  else:
228
  print("No person detected by yolo_person_model. Analyzing full image.")
229
 
230
- # 2) YOLO Fashion Model Detection (run on the cropped image if person was found)
231
  detected_fashion_item_name = None
232
  detected_fashion_item_conf = 0.0
233
- if person_detected or True: # Or always run on the (potentially full) image? Let's always run for now.
234
  try:
235
  fashion_results = yolo_fashion_model(cropped_img, verbose=False, conf=YOLO_FASHION_CONF_THRESHOLD)
236
  fashion_boxes = fashion_results[0].boxes.xyxy.cpu().numpy()
@@ -238,7 +227,7 @@ def analyze_outfit(input_img):
238
  fashion_confidences = fashion_results[0].boxes.conf.cpu().numpy()
239
 
240
  if len(fashion_classes) > 0:
241
- # Find the detection with the highest confidence
242
  best_fashion_idx = np.argmax(fashion_confidences)
243
  detected_class_id = fashion_classes[best_fashion_idx]
244
  detected_fashion_item_conf = fashion_confidences[best_fashion_idx]
@@ -256,7 +245,7 @@ def analyze_outfit(input_img):
256
  print(f"Error during YOLO fashion model analysis: {e}")
257
  # Continue without fashion model input
258
 
259
- # 3) CLIP Analysis (always run on the cropped/full image)
260
  clip_detected_item = "look" # Default fallback item name
261
  clip_detected_item_prob = 0.0
262
  category_key = 'mid' # Default category
@@ -270,7 +259,7 @@ def analyze_outfit(input_img):
270
  logits, _ = clip_model(image_tensor, text_tokens)
271
  all_probs = logits.softmax(dim=-1).cpu().numpy()[0]
272
 
273
- # Calculate style scores
274
  drip_len = len(style_prompts['drippy'])
275
  mid_len = len(style_prompts['mid'])
276
  drip_score = np.mean(all_probs[0 : drip_len])
@@ -282,37 +271,35 @@ def analyze_outfit(input_img):
282
  if drip_score > 0.41 and drip_score > mid_score and drip_score > not_score:
283
  category_key = 'drippy'
284
  final_score = drip_score
285
- score_label = "Drip Score" # <<< DEFINE score_label
286
- elif mid_score > not_score: # Check mid_score > not_score explicitly
287
  category_key = 'mid'
288
  final_score = mid_score
289
- score_label = "Mid Score" # <<< DEFINE score_label
290
  else:
291
  category_key = 'not_drippy'
292
  final_score = not_score
293
- score_label = "Trash Score" # <<< DEFINE score_label # Or maybe "Rating Score"
294
 
295
  category_label = CATEGORY_LABEL_MAP[category_key]
296
- # final_score_str = f"{final_score:.2f}" # You might not need this raw score string anymore
297
  percentage_score = max(0, final_score * 100)
298
- percentage_score_str = f"{percentage_score:.0f}%" # Formats as integer (e.g., "3%", "15%", "0%")
299
 
300
- # Now score_label is defined before being used here
301
  print(f"Style analysis: Category={category_label}, Score = {score_label}={percentage_score_str} (Raw Score: {final_score:.4f})")
302
 
303
  # Get top clothing item from CLIP
304
- top_3_clip_items = get_top_clip_clothing(all_probs, n=3) # <<< Ask for top 3 items
305
 
306
  if top_3_clip_items:
307
- # Print the top 3 detected items
308
  detected_items_str = ", ".join([f"{item[0]} ({item[1]*100:.1f}%)" for item in top_3_clip_items]) # Show item and probability
309
  print(f"I think I detected: {detected_items_str}")
310
 
311
- # Still use the single *most* probable item for response generation logic later
312
  clip_detected_item, clip_detected_item_prob = top_3_clip_items[0]
313
- # Optional: You can keep or remove the print for the single top item below if the top-3 print is sufficient
314
- # print(f"Top clothing item identified by CLIP (for response): '{clip_detected_item}' "
315
- # f"with probability {clip_detected_item_prob:.2f}")
316
  else:
317
  print("I couldn't confidently identify specific clothing items via CLIP.")
318
  clip_detected_item = "piece" # Use a different fallback if CLIP fails
@@ -320,7 +307,7 @@ def analyze_outfit(input_img):
320
 
321
  except Exception as e:
322
  print(f"Error during CLIP analysis: {e}")
323
- # Use defaults, maybe return error message?
324
  return ("<p style='color: #FF5555;'>Error during CLIP analysis.</p>",
325
  None, f"Analysis Error: {e}")
326
 
@@ -347,10 +334,10 @@ def analyze_outfit(input_img):
347
  print(f"Using generic fallback item: '{final_clothing_item}'")
348
 
349
 
350
- # 5) Generate Response and TTS
351
  try:
352
  response_pool = response_templates[category_key]
353
- # Choose a random template from the entire response pool
354
  chosen_template = random.choice(response_pool)
355
 
356
  # Format the response, substituting the item name if needed
@@ -561,10 +548,9 @@ custom_css = """:root {
561
  gap: 25px !important;
562
  }"""
563
 
564
- # --- Gradio Interface (Using the custom CSS) ---
565
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
566
- #gr.Markdown("<h1 style='text-align: center;'>💧 DripAI: Rate Your Fit 💧</h1>")
567
- #gr.Markdown("<p style='text-align: center; font-style: italic;'>AI-powered fashion judgment. Zero mercy.</p>")
568
 
569
  with gr.Row():
570
  with gr.Column(scale=1):
@@ -575,7 +561,7 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
575
  sources=['upload', 'webcam', 'clipboard'],
576
  height=400,
577
  show_label=False
578
- #webcam_options=gr.WebcamOptions(mirror_webcam=False)
579
  )
580
  analyze_button = gr.Button("🔥 Analyze This Drip", variant="primary")
581
 
@@ -595,17 +581,14 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
595
  inputs=[input_image],
596
  outputs=[category_html, audio_output, response_box]
597
  )
598
- #gr.Markdown("<p>Upload, paste, or use your camera to capture your outfit using the three icons. DripAI evaluates your style using multiple AI models.</p>")
599
-
600
- # --- Launch App ---
601
  if __name__ == "__main__":
602
- # Make sure 'best.pt' is in the same directory or provide the full path
603
  if not os.path.exists(YOLO_FASHION_MODEL_PATH):
604
  print(f"\n{'='*20} WARNING {'='*20}")
605
  print(f"Fashion model file '{YOLO_FASHION_MODEL_PATH}' not found!")
606
  print(f"The app will run but fashion item detection will be skipped.")
607
  print(f"{'='*50}\n")
608
- # Optionally, you could disable the fashion model part entirely here
609
- # or raise an error if it's critical.
610
 
611
- demo.launch(debug=True, show_error=True) # Set debug=False for deployment
 
5
  import random
6
  import os
7
  from PIL import Image
8
+ from ultralytics import YOLO
9
  from gtts import gTTS
10
  import uuid
11
  import time
12
  import tempfile
13
  from huggingface_hub import hf_hub_download
14
+
 
 
15
  HF_TOKEN = os.environ.get("HF_TOKEN")
16
 
17
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
 
31
  CLIP_MODEL_NAME = "ViT-B/32"
32
 
33
  # Confidence Thresholds
34
+ YOLO_PERSON_CONF_THRESHOLD = 0.4
35
+ YOLO_FASHION_CONF_THRESHOLD = 0.4
36
+ YOLO_FASHION_HIGH_CONF_THRESHOLD = 0.6
37
+
38
 
 
39
  FASHION_CLASSES = {
40
  0: 'long sleeve top', 1: 'skirt', 2: 'trousers', 3: 'short sleeve top',
41
  4: 'long sleeve outwear', 5: 'short sleeve dress', 6: 'shorts',
 
44
  }
45
  print(f"Defined {len(FASHION_CLASSES)} fashion categories for {YOLO_FASHION_MODEL_PATH}")
46
 
 
47
  print(f"Using device: {DEVICE}")
48
  try:
49
  clip_model, clip_preprocess = clip.load(CLIP_MODEL_NAME, device=DEVICE)
50
  print(f"CLIP model ({CLIP_MODEL_NAME}) loaded successfully.")
51
  except Exception as e:
52
  print(f"Error loading CLIP model: {e}")
53
+
54
 
55
  try:
56
+ yolo_person_model = YOLO(YOLO_PERSON_MODEL_PATH)
57
  print(f"YOLO person detection model ({YOLO_PERSON_MODEL_PATH}) loaded successfully.")
58
  except Exception as e:
59
  print(f"Error loading YOLO person model: {e}")
60
+
61
 
62
  try:
63
  yolo_fashion_model = YOLO(YOLO_FASHION_MODEL_PATH) # No .to(DEVICE) needed here
64
  print(f"YOLO fashion detection model ({YOLO_FASHION_MODEL_PATH}) loaded successfully.")
65
  except Exception as e:
66
  print(f"Error loading YOLO fashion model: {e}")
 
67
 
 
68
  style_prompts = {
69
  'drippy': [
70
  "avant-garde streetwear", "high-fashion designer outfit", "trendsetting urban attire",
 
80
  ]
81
  }
82
 
83
+
84
  clothing_prompts = [
85
  "t-shirt", "dress shirt", "blouse", "hoodie", "jacket", "sweater", "coat",
86
  "dress", "skirt", "pants", "jeans", "trousers", "shorts",
 
88
  "cap", "hat", "scarf", "gloves", "bag", "accessory", "tank-top", "haircut"
89
  ]
90
 
91
+
92
  all_prompts = []
93
  for cat_prompts in style_prompts.values():
94
  all_prompts.extend(cat_prompts)
95
+ style_prompts_end_index = len(all_prompts)
96
  all_prompts.extend(clothing_prompts)
 
97
 
98
+
99
+
100
  response_templates = {
101
  'drippy': [
102
  "You're Drippy, bruh – fire {item}!",
 
135
  return ""
136
  return "<p class='result-items'>Detected items: " + ", ".join(item_list) + "</p>"
137
 
138
+
139
  def get_top_clip_clothing(probs, n=1):
140
  """Gets the top N clothing items based on CLIP probabilities."""
141
  clothing_probs_start_index = style_prompts_end_index
142
  clothing_probs = probs[clothing_probs_start_index:]
143
  actual_n = min(n, len(clothing_prompts))
144
  if actual_n <= 0:
145
+ return []
146
+
147
 
 
148
  top_indices_in_slice = np.argsort(clothing_probs)[-actual_n:]
149
+
150
  top_global_indices = [idx + clothing_probs_start_index for idx in top_indices_in_slice]
151
 
152
+
153
  top_items_with_probs = [
154
  (clothing_prompts[i], clothing_probs[i])
155
+ for i in reversed(top_indices_in_slice)
156
  ]
157
  return top_items_with_probs
158
  def wrapped_analyze(input_img):
 
173
  DEVICE
174
  )
175
  def analyze_outfit(input_img):
176
+
177
  if isinstance(input_img, str):
178
  try:
179
  input_img = Image.open(input_img)
 
181
  return (f"<p style='color: #FF5555;'>Error loading image: {str(e)}</p>",
182
  None, "Image loading error")
183
 
184
+
185
  if input_img is None:
186
  return ("<p style='color: #FF5555; text-align: center;'>Please upload an image.</p>",
187
  None, "Error: No image provided.")
188
 
189
  img = input_img.convert("RGB").copy()
 
 
 
 
 
190
 
 
191
  person_results = yolo_person_model(img, verbose=False, conf=YOLO_PERSON_CONF_THRESHOLD)
192
  boxes = person_results[0].boxes.xyxy.cpu().numpy()
193
  classes = person_results[0].boxes.cls.cpu().numpy()
194
  confidences = person_results[0].boxes.conf.cpu().numpy()
195
 
196
+
197
  person_indices = np.where(classes == 0)[0]
198
+ cropped_img = img
199
  person_detected = False
200
 
201
  if len(person_indices) > 0:
202
+
203
  max_conf_person_idx = person_indices[np.argmax(confidences[person_indices])]
204
  x1, y1, x2, y2 = map(int, boxes[max_conf_person_idx])
205
+
206
  x1, y1 = max(0, x1), max(0, y1)
207
  x2, y2 = min(img.width, x2), min(img.height, y2)
208
 
209
+ if x1 < x2 and y1 < y2:
210
  cropped_img = img.crop((x1, y1, x2, y2))
211
  print(f"Person detected and cropped: Box {x1, y1, x2, y2}")
212
  person_detected = True
 
216
  else:
217
  print("No person detected by yolo_person_model. Analyzing full image.")
218
 
219
+
220
  detected_fashion_item_name = None
221
  detected_fashion_item_conf = 0.0
222
+ if person_detected or True:
223
  try:
224
  fashion_results = yolo_fashion_model(cropped_img, verbose=False, conf=YOLO_FASHION_CONF_THRESHOLD)
225
  fashion_boxes = fashion_results[0].boxes.xyxy.cpu().numpy()
 
227
  fashion_confidences = fashion_results[0].boxes.conf.cpu().numpy()
228
 
229
  if len(fashion_classes) > 0:
230
+
231
  best_fashion_idx = np.argmax(fashion_confidences)
232
  detected_class_id = fashion_classes[best_fashion_idx]
233
  detected_fashion_item_conf = fashion_confidences[best_fashion_idx]
 
245
  print(f"Error during YOLO fashion model analysis: {e}")
246
  # Continue without fashion model input
247
 
248
+
249
  clip_detected_item = "look" # Default fallback item name
250
  clip_detected_item_prob = 0.0
251
  category_key = 'mid' # Default category
 
259
  logits, _ = clip_model(image_tensor, text_tokens)
260
  all_probs = logits.softmax(dim=-1).cpu().numpy()[0]
261
 
262
+
263
  drip_len = len(style_prompts['drippy'])
264
  mid_len = len(style_prompts['mid'])
265
  drip_score = np.mean(all_probs[0 : drip_len])
 
271
  if drip_score > 0.41 and drip_score > mid_score and drip_score > not_score:
272
  category_key = 'drippy'
273
  final_score = drip_score
274
+ score_label = "Drip Score"
275
+ elif mid_score > not_score:
276
  category_key = 'mid'
277
  final_score = mid_score
278
+ score_label = "Mid Score"
279
  else:
280
  category_key = 'not_drippy'
281
  final_score = not_score
282
+ score_label = "Trash Score"
283
 
284
  category_label = CATEGORY_LABEL_MAP[category_key]
285
+
286
  percentage_score = max(0, final_score * 100)
287
+ percentage_score_str = f"{percentage_score:.0f}%"
288
 
289
+
290
  print(f"Style analysis: Category={category_label}, Score = {score_label}={percentage_score_str} (Raw Score: {final_score:.4f})")
291
 
292
  # Get top clothing item from CLIP
293
+ top_3_clip_items = get_top_clip_clothing(all_probs, n=3)
294
 
295
  if top_3_clip_items:
296
+
297
  detected_items_str = ", ".join([f"{item[0]} ({item[1]*100:.1f}%)" for item in top_3_clip_items]) # Show item and probability
298
  print(f"I think I detected: {detected_items_str}")
299
 
300
+
301
  clip_detected_item, clip_detected_item_prob = top_3_clip_items[0]
302
+
 
 
303
  else:
304
  print("I couldn't confidently identify specific clothing items via CLIP.")
305
  clip_detected_item = "piece" # Use a different fallback if CLIP fails
 
307
 
308
  except Exception as e:
309
  print(f"Error during CLIP analysis: {e}")
310
+
311
  return ("<p style='color: #FF5555;'>Error during CLIP analysis.</p>",
312
  None, f"Analysis Error: {e}")
313
 
 
334
  print(f"Using generic fallback item: '{final_clothing_item}'")
335
 
336
 
337
+
338
  try:
339
  response_pool = response_templates[category_key]
340
+
341
  chosen_template = random.choice(response_pool)
342
 
343
  # Format the response, substituting the item name if needed
 
548
  gap: 25px !important;
549
  }"""
550
 
551
+
552
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
553
+
 
554
 
555
  with gr.Row():
556
  with gr.Column(scale=1):
 
561
  sources=['upload', 'webcam', 'clipboard'],
562
  height=400,
563
  show_label=False
564
+
565
  )
566
  analyze_button = gr.Button("🔥 Analyze This Drip", variant="primary")
567
 
 
581
  inputs=[input_image],
582
  outputs=[category_html, audio_output, response_box]
583
  )
584
+
 
 
585
  if __name__ == "__main__":
586
+
587
  if not os.path.exists(YOLO_FASHION_MODEL_PATH):
588
  print(f"\n{'='*20} WARNING {'='*20}")
589
  print(f"Fashion model file '{YOLO_FASHION_MODEL_PATH}' not found!")
590
  print(f"The app will run but fashion item detection will be skipped.")
591
  print(f"{'='*50}\n")
592
+
 
593
 
594
+ demo.launch(debug=False, show_error=True) # Set debug=False for deployment