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:
2026-04-21 18:53:04 +03:00
parent 76fa22bba9
commit ada3669217
5 changed files with 525 additions and 8 deletions

View File

@@ -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)