Spaces:
Sleeping
Sleeping
Add image_name field support for JSON import - match images by filename
Browse files
app.py
CHANGED
|
@@ -1197,8 +1197,10 @@ with gr.Blocks(
|
|
| 1197 |
with gr.Tab("Bulk Import (JSON)"):
|
| 1198 |
gr.Markdown(
|
| 1199 |
"Paste a JSON array like: `[{\"input\": \"...\", \"output\": \"...\"}]`<br>"
|
| 1200 |
-
"**Images**: Upload images below and reference them
|
| 1201 |
-
"
|
|
|
|
|
|
|
| 1202 |
elem_classes=["small-note"]
|
| 1203 |
)
|
| 1204 |
bulk_json = gr.Textbox(
|
|
@@ -1450,29 +1452,57 @@ with gr.Blocks(
|
|
| 1450 |
raise gr.Error("JSON array is empty. Add at least one example object.")
|
| 1451 |
|
| 1452 |
# Process uploaded images into base64 format
|
|
|
|
| 1453 |
image_list = []
|
|
|
|
|
|
|
|
|
|
| 1454 |
if uploaded_images:
|
| 1455 |
for img_file in uploaded_images:
|
| 1456 |
try:
|
| 1457 |
if img_file is None:
|
| 1458 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1459 |
# Handle different file input formats
|
| 1460 |
if isinstance(img_file, str):
|
| 1461 |
# File path
|
| 1462 |
if os.path.exists(img_file):
|
|
|
|
| 1463 |
img_b64 = gradio_image_to_base64(img_file)
|
| 1464 |
-
if img_b64:
|
| 1465 |
-
image_list.append(img_b64)
|
| 1466 |
elif hasattr(img_file, 'name'):
|
| 1467 |
-
# File object with name attribute
|
|
|
|
| 1468 |
img_b64 = gradio_image_to_base64(img_file.name)
|
| 1469 |
-
|
| 1470 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1471 |
else:
|
| 1472 |
# Try to process as image directly
|
| 1473 |
img_b64 = gradio_image_to_base64(img_file)
|
| 1474 |
-
|
| 1475 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1476 |
except Exception as e:
|
| 1477 |
logger.warning(f"Failed to process uploaded image: {str(e)}")
|
| 1478 |
continue
|
|
@@ -1502,9 +1532,43 @@ with gr.Blocks(
|
|
| 1502 |
errors.append(f"Item {i+1}: 'input' and 'output' cannot be empty")
|
| 1503 |
continue
|
| 1504 |
|
| 1505 |
-
# Handle image - check for
|
| 1506 |
img_b64 = None
|
| 1507 |
-
if "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1508 |
# Reference uploaded image by index
|
| 1509 |
img_idx = item["image_index"]
|
| 1510 |
if not isinstance(img_idx, int):
|
|
|
|
| 1197 |
with gr.Tab("Bulk Import (JSON)"):
|
| 1198 |
gr.Markdown(
|
| 1199 |
"Paste a JSON array like: `[{\"input\": \"...\", \"output\": \"...\"}]`<br>"
|
| 1200 |
+
"**Images**: Upload images below and reference them in JSON using:<br>"
|
| 1201 |
+
"• `\"image_name\": \"filename.png\"` - Match by filename (recommended)<br>"
|
| 1202 |
+
"• `\"image_index\": 0` - Reference by upload order (0-based)<br>"
|
| 1203 |
+
"• `\"image\": \"data:image/...\"` - Include base64 directly",
|
| 1204 |
elem_classes=["small-note"]
|
| 1205 |
)
|
| 1206 |
bulk_json = gr.Textbox(
|
|
|
|
| 1452 |
raise gr.Error("JSON array is empty. Add at least one example object.")
|
| 1453 |
|
| 1454 |
# Process uploaded images into base64 format
|
| 1455 |
+
# Create both a list (for index-based access) and a dict (for filename-based access)
|
| 1456 |
image_list = []
|
| 1457 |
+
image_dict = {} # Maps filename -> base64
|
| 1458 |
+
original_filenames = [] # Track original filenames for error messages
|
| 1459 |
+
|
| 1460 |
if uploaded_images:
|
| 1461 |
for img_file in uploaded_images:
|
| 1462 |
try:
|
| 1463 |
if img_file is None:
|
| 1464 |
continue
|
| 1465 |
+
|
| 1466 |
+
# Extract filename and process image
|
| 1467 |
+
filename = None
|
| 1468 |
+
img_b64 = None
|
| 1469 |
+
|
| 1470 |
# Handle different file input formats
|
| 1471 |
if isinstance(img_file, str):
|
| 1472 |
# File path
|
| 1473 |
if os.path.exists(img_file):
|
| 1474 |
+
filename = os.path.basename(img_file)
|
| 1475 |
img_b64 = gradio_image_to_base64(img_file)
|
|
|
|
|
|
|
| 1476 |
elif hasattr(img_file, 'name'):
|
| 1477 |
+
# File object with name attribute (Gradio File object)
|
| 1478 |
+
filename = os.path.basename(img_file.name) if img_file.name else None
|
| 1479 |
img_b64 = gradio_image_to_base64(img_file.name)
|
| 1480 |
+
elif isinstance(img_file, dict):
|
| 1481 |
+
# Gradio file dict format: {"name": "...", "path": "...", ...}
|
| 1482 |
+
file_path = img_file.get("path") or img_file.get("name")
|
| 1483 |
+
if file_path:
|
| 1484 |
+
filename = os.path.basename(file_path)
|
| 1485 |
+
img_b64 = gradio_image_to_base64(file_path)
|
| 1486 |
else:
|
| 1487 |
# Try to process as image directly
|
| 1488 |
img_b64 = gradio_image_to_base64(img_file)
|
| 1489 |
+
# If we can't get filename, use index as fallback
|
| 1490 |
+
filename = f"image_{len(image_list)}.png"
|
| 1491 |
+
|
| 1492 |
+
if img_b64:
|
| 1493 |
+
image_list.append(img_b64)
|
| 1494 |
+
# Store by filename (case-insensitive matching)
|
| 1495 |
+
if filename:
|
| 1496 |
+
original_filenames.append(filename)
|
| 1497 |
+
# Store with original filename
|
| 1498 |
+
image_dict[filename] = img_b64
|
| 1499 |
+
# Also store with lowercase for case-insensitive lookup
|
| 1500 |
+
image_dict[filename.lower()] = img_b64
|
| 1501 |
+
# Also store without extension for more flexible matching
|
| 1502 |
+
base_name = os.path.splitext(filename)[0]
|
| 1503 |
+
if base_name and base_name != filename:
|
| 1504 |
+
image_dict[base_name] = img_b64
|
| 1505 |
+
image_dict[base_name.lower()] = img_b64
|
| 1506 |
except Exception as e:
|
| 1507 |
logger.warning(f"Failed to process uploaded image: {str(e)}")
|
| 1508 |
continue
|
|
|
|
| 1532 |
errors.append(f"Item {i+1}: 'input' and 'output' cannot be empty")
|
| 1533 |
continue
|
| 1534 |
|
| 1535 |
+
# Handle image - check for image_name first, then image_index, then direct image field
|
| 1536 |
img_b64 = None
|
| 1537 |
+
if "image_name" in item:
|
| 1538 |
+
# Match uploaded image by filename
|
| 1539 |
+
image_name = item["image_name"]
|
| 1540 |
+
if not isinstance(image_name, str):
|
| 1541 |
+
errors.append(f"Item {i+1}: 'image_name' must be a string")
|
| 1542 |
+
continue
|
| 1543 |
+
if not image_name.strip():
|
| 1544 |
+
errors.append(f"Item {i+1}: 'image_name' cannot be empty")
|
| 1545 |
+
continue
|
| 1546 |
+
|
| 1547 |
+
# Try to find matching image (case-insensitive)
|
| 1548 |
+
image_name_clean = image_name.strip()
|
| 1549 |
+
img_b64 = image_dict.get(image_name_clean) or image_dict.get(image_name_clean.lower())
|
| 1550 |
+
|
| 1551 |
+
if not img_b64:
|
| 1552 |
+
# Try matching just the filename without path
|
| 1553 |
+
basename = os.path.basename(image_name_clean)
|
| 1554 |
+
img_b64 = image_dict.get(basename) or image_dict.get(basename.lower())
|
| 1555 |
+
|
| 1556 |
+
if not img_b64:
|
| 1557 |
+
# Try matching without extension
|
| 1558 |
+
base_name = os.path.splitext(image_name_clean)[0]
|
| 1559 |
+
if base_name:
|
| 1560 |
+
img_b64 = image_dict.get(base_name) or image_dict.get(base_name.lower())
|
| 1561 |
+
|
| 1562 |
+
if not img_b64:
|
| 1563 |
+
# Show available filenames for debugging
|
| 1564 |
+
available_str = ', '.join(original_filenames[:5])
|
| 1565 |
+
if len(original_filenames) > 5:
|
| 1566 |
+
available_str += f" (and {len(original_filenames) - 5} more)"
|
| 1567 |
+
if not original_filenames:
|
| 1568 |
+
available_str = "none uploaded"
|
| 1569 |
+
# Log warning but continue - don't fail the entire import
|
| 1570 |
+
logger.warning(f"Item {i+1}: Image '{image_name}' not found. Available images: {available_str}")
|
| 1571 |
+
elif "image_index" in item:
|
| 1572 |
# Reference uploaded image by index
|
| 1573 |
img_idx = item["image_index"]
|
| 1574 |
if not isinstance(img_idx, int):
|