Spaces:
Runtime error
Runtime error
feat(ui): add capture mode selector (single/multi/video WIP)
Browse filesAdd a Radio selector in the Capture tab with three modes:
- Single garment: skips YOLO, sends photo directly to VLM with
single-garment prompt (ideal for close-up photos)
- Multiple garments: full pipeline (YOLO + crops + VLM per crop,
fallback to multi-garment VLM analysis)
- Video stream: placeholder showing "coming soon" message
New vision.extract_single_from_path() for direct single-garment
extraction without YOLO detection step.
Co-authored-by: Cursor <cursoragent@cursor.com>
- app.py +21 -5
- src/vision.py +15 -0
app.py
CHANGED
|
@@ -11,7 +11,7 @@ import os
|
|
| 11 |
|
| 12 |
import gradio as gr
|
| 13 |
|
| 14 |
-
from src.vision import extract_garments
|
| 15 |
from src.catalog import (
|
| 16 |
add_garments,
|
| 17 |
load_catalog,
|
|
@@ -47,16 +47,23 @@ mediante lenguaje natural. Sube fotos → detecta prendas → pregunta lo que qu
|
|
| 47 |
"""
|
| 48 |
|
| 49 |
|
| 50 |
-
def analyze_images(images):
|
| 51 |
-
"""Process uploaded images and extract garments."""
|
| 52 |
if not images:
|
| 53 |
return "Sube al menos una imagen.", []
|
| 54 |
|
|
|
|
|
|
|
|
|
|
| 55 |
all_added = []
|
| 56 |
for img_data in images:
|
| 57 |
image_path = img_data if isinstance(img_data, str) else img_data.name
|
| 58 |
try:
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
if garments_with_crops:
|
| 61 |
added = add_garments(garments_with_crops)
|
| 62 |
all_added.extend(added)
|
|
@@ -295,6 +302,15 @@ with gr.Blocks(title="Wardrobe AI") as demo:
|
|
| 295 |
|
| 296 |
with gr.Row():
|
| 297 |
with gr.Column(scale=1):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
image_input = gr.File(
|
| 299 |
label="Fotos del armario",
|
| 300 |
file_count="multiple",
|
|
@@ -313,7 +329,7 @@ with gr.Blocks(title="Wardrobe AI") as demo:
|
|
| 313 |
|
| 314 |
analyze_btn.click(
|
| 315 |
analyze_images,
|
| 316 |
-
inputs=[image_input],
|
| 317 |
outputs=[status_output, detected_table],
|
| 318 |
)
|
| 319 |
|
|
|
|
| 11 |
|
| 12 |
import gradio as gr
|
| 13 |
|
| 14 |
+
from src.vision import extract_garments, extract_single_from_path
|
| 15 |
from src.catalog import (
|
| 16 |
add_garments,
|
| 17 |
load_catalog,
|
|
|
|
| 47 |
"""
|
| 48 |
|
| 49 |
|
| 50 |
+
def analyze_images(images, mode):
|
| 51 |
+
"""Process uploaded images and extract garments based on capture mode."""
|
| 52 |
if not images:
|
| 53 |
return "Sube al menos una imagen.", []
|
| 54 |
|
| 55 |
+
if mode == "video":
|
| 56 |
+
return "Video stream estará disponible próximamente.", []
|
| 57 |
+
|
| 58 |
all_added = []
|
| 59 |
for img_data in images:
|
| 60 |
image_path = img_data if isinstance(img_data, str) else img_data.name
|
| 61 |
try:
|
| 62 |
+
if mode == "single":
|
| 63 |
+
garments_with_crops = extract_single_from_path(image_path)
|
| 64 |
+
else:
|
| 65 |
+
garments_with_crops = extract_garments(image_path)
|
| 66 |
+
|
| 67 |
if garments_with_crops:
|
| 68 |
added = add_garments(garments_with_crops)
|
| 69 |
all_added.extend(added)
|
|
|
|
| 302 |
|
| 303 |
with gr.Row():
|
| 304 |
with gr.Column(scale=1):
|
| 305 |
+
capture_mode = gr.Radio(
|
| 306 |
+
choices=[
|
| 307 |
+
("Prenda individual", "single"),
|
| 308 |
+
("Múltiples prendas", "multi"),
|
| 309 |
+
("Video stream (próximamente)", "video"),
|
| 310 |
+
],
|
| 311 |
+
value="multi",
|
| 312 |
+
label="Modo de captura",
|
| 313 |
+
)
|
| 314 |
image_input = gr.File(
|
| 315 |
label="Fotos del armario",
|
| 316 |
file_count="multiple",
|
|
|
|
| 329 |
|
| 330 |
analyze_btn.click(
|
| 331 |
analyze_images,
|
| 332 |
+
inputs=[image_input, capture_mode],
|
| 333 |
outputs=[status_output, detected_table],
|
| 334 |
)
|
| 335 |
|
src/vision.py
CHANGED
|
@@ -220,3 +220,18 @@ def extract_garments(image_path: str) -> list[tuple[dict, bytes]]:
|
|
| 220 |
logger.info("Falling back to full-image analysis")
|
| 221 |
garments, full_bytes = _extract_from_full_image(image_path)
|
| 222 |
return [(g, full_bytes) for g in garments]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
logger.info("Falling back to full-image analysis")
|
| 221 |
garments, full_bytes = _extract_from_full_image(image_path)
|
| 222 |
return [(g, full_bytes) for g in garments]
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def extract_single_from_path(image_path: str) -> list[tuple[dict, bytes]]:
|
| 226 |
+
"""Extract a single garment from a photo (no YOLO, direct VLM).
|
| 227 |
+
|
| 228 |
+
Use when the user photographs one garment at a time.
|
| 229 |
+
Returns a list with 0 or 1 (garment_dict, image_bytes) tuples.
|
| 230 |
+
"""
|
| 231 |
+
logger.info("Single-garment mode: %s", image_path)
|
| 232 |
+
_, image_bytes = _prepare_image(image_path)
|
| 233 |
+
garment = _extract_single_garment(image_bytes)
|
| 234 |
+
|
| 235 |
+
if garment:
|
| 236 |
+
return [(garment, image_bytes)]
|
| 237 |
+
return []
|