test: add tests for image_processing field from AI extraction
- Added 11 comprehensive tests for image_processing parsing
- Tests validate crop_bounds structure: {x, y, width, height} all ints >= 0
- Tests validate rotation_degrees: int/float, -360 to +360
- Tests validate confidence: float, 0.0 to 1.0
- Tests graceful handling when image_processing field is missing
- Tests multiple items with image_processing data
- Tests partial data handling (optional fields)
- Tests with both Gemini and Claude providers
- Updated extract_label_info() to preserve and validate image_processing field
- All tests passing, no regressions
This commit is contained in:
@@ -103,7 +103,7 @@ def extract_label_info(image_bytes: bytes, mode: str = "item"):
|
||||
"PartNr": "part_number",
|
||||
"OCR": "ocr_text"
|
||||
}
|
||||
|
||||
|
||||
mapped_items = []
|
||||
for item_data in items_to_map:
|
||||
final_item = {}
|
||||
@@ -113,17 +113,46 @@ def extract_label_info(image_bytes: bytes, mode: str = "item"):
|
||||
final_item[model_key] = val.strip()
|
||||
else:
|
||||
final_item[model_key] = val
|
||||
|
||||
|
||||
# Default fields
|
||||
final_item["quantity"] = item_data.get("quantity", 1)
|
||||
raw_barcode = item_data.get("barcode") or item_data.get("PartNr") or item_data.get("part_number") or item_data.get("Part Number")
|
||||
final_item["barcode"] = str(raw_barcode).strip() if raw_barcode else f"AI-{int(time.time()*100)}"
|
||||
|
||||
|
||||
# Handle Box mode specifically inside mapping
|
||||
if mode == "box":
|
||||
final_item["box_label"] = final_item.get("box_label") or item_data.get("Box") or final_item.get("name") or "Unknown Box"
|
||||
final_item["name"] = final_item["box_label"]
|
||||
|
||||
|
||||
# Extract image_processing field if present (optional, graceful fallback)
|
||||
if "image_processing" in item_data and item_data["image_processing"]:
|
||||
image_proc = item_data["image_processing"]
|
||||
# Validate and preserve image_processing
|
||||
validated_proc = {}
|
||||
|
||||
# Validate crop_bounds
|
||||
if "crop_bounds" in image_proc and isinstance(image_proc["crop_bounds"], dict):
|
||||
bounds = image_proc["crop_bounds"]
|
||||
if all(k in bounds for k in ["x", "y", "width", "height"]):
|
||||
if all(isinstance(bounds[k], int) and bounds[k] >= 0 for k in ["x", "y", "width", "height"]):
|
||||
validated_proc["crop_bounds"] = bounds
|
||||
|
||||
# Validate rotation_degrees
|
||||
if "rotation_degrees" in image_proc:
|
||||
rotation = image_proc["rotation_degrees"]
|
||||
if isinstance(rotation, (int, float)) and -360 <= rotation <= 360:
|
||||
validated_proc["rotation_degrees"] = rotation
|
||||
|
||||
# Validate confidence
|
||||
if "confidence" in image_proc:
|
||||
confidence = image_proc["confidence"]
|
||||
if isinstance(confidence, (int, float)) and 0.0 <= confidence <= 1.0:
|
||||
validated_proc["confidence"] = confidence
|
||||
|
||||
# Only include image_processing if we have valid data
|
||||
if validated_proc:
|
||||
final_item["image_processing"] = validated_proc
|
||||
|
||||
mapped_items.append(final_item)
|
||||
|
||||
# Return either the whole list wrapper or the first item (legacy compatibility)
|
||||
|
||||
Reference in New Issue
Block a user