devZenaight commited on
Commit
d68e5fd
·
1 Parent(s): b4d4ce5

Confidence + Bucket

Browse files

It crops to the highest confidence score instead of largest box.

The bucket or receipts will now be stored in their correct folders corresponding to their category

Files changed (1) hide show
  1. app.py +59 -9
app.py CHANGED
@@ -349,28 +349,62 @@ def parse_total(value: str | float | int | None) -> float:
349
  return float(m[-1]) if m else 0.0
350
 
351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  def detect_and_crop_largest_receipt(img_array: np.ndarray):
353
- """Detect the largest bounding box via YOLO and return crop and bbox.
354
 
355
  Returns (cropped_array, bbox_dict)
356
- bbox_dict = {"x1": int, "y1": int, "x2": int, "y2": int}
357
  """
358
  results = model(img_array)
359
- # Default fallback to full image
360
  cropped = img_array
361
  bbox = None
 
362
  for r in results:
363
  if len(r.boxes.xyxy) == 0:
364
  continue
365
- boxes = r.boxes.xyxy
366
- i = max(range(len(boxes)), key=lambda j: (boxes[j][2]-boxes[j][0]) * (boxes[j][3]-boxes[j][1]))
 
 
 
 
 
367
  x1, y1, x2, y2 = map(int, boxes[i].tolist())
368
  cropped = img_array[y1:y2, x1:x2]
369
- bbox = {"x1": x1, "y1": y1, "x2": x2, "y2": y2}
370
- break
 
 
 
 
 
 
 
371
  return cropped, bbox
372
 
373
 
 
374
  def encode_image_to_data_url(img_array: np.ndarray, format: str = "JPEG") -> str:
375
  """Encode an RGB image array to a data URL suitable for GPT-4o image input."""
376
  pil_img = Image.fromarray(img_array)
@@ -540,11 +574,27 @@ async def process_receipt_vision(
540
  content_str = getattr(result, "content", str(result))
541
  extracted_obj = parse_extracted_json(content_str)
542
 
543
- # Upload CROPPED image to Storage (JPEG)
544
  cropped_bytes = encode_image_to_jpeg_bytes(cropped)
545
- storage_path = f"{user_id}/{int(time.time()*1000)}_cropped.jpg"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
546
  try:
547
  stored = upload_to_storage(storage_path, cropped_bytes, "image/jpeg")
 
548
  except Exception as exc:
549
  from fastapi import HTTPException
550
  raise HTTPException(status_code=502, detail=f"Storage upload failed: {exc}")
 
349
  return float(m[-1]) if m else 0.0
350
 
351
 
352
+ # def detect_and_crop_largest_receipt(img_array: np.ndarray):
353
+ # """Detect the largest bounding box via YOLO and return crop and bbox.
354
+
355
+ # Returns (cropped_array, bbox_dict)
356
+ # bbox_dict = {"x1": int, "y1": int, "x2": int, "y2": int}
357
+ # """
358
+ # results = model(img_array)
359
+ # # Default fallback to full image
360
+ # cropped = img_array
361
+ # bbox = None
362
+ # for r in results:
363
+ # if len(r.boxes.xyxy) == 0:
364
+ # continue
365
+ # boxes = r.boxes.xyxy
366
+ # i = max(range(len(boxes)), key=lambda j: (boxes[j][2]-boxes[j][0]) * (boxes[j][3]-boxes[j][1]))
367
+ # x1, y1, x2, y2 = map(int, boxes[i].tolist())
368
+ # cropped = img_array[y1:y2, x1:x2]
369
+ # bbox = {"x1": x1, "y1": y1, "x2": x2, "y2": y2}
370
+ # break
371
+ # return cropped, bbox
372
+
373
  def detect_and_crop_largest_receipt(img_array: np.ndarray):
374
+ """Detect receipt via YOLO and return the crop of the highest-confidence box.
375
 
376
  Returns (cropped_array, bbox_dict)
377
+ bbox_dict = {"x1": int, "y1": int, "x2": int, "y2": int, "conf": float}
378
  """
379
  results = model(img_array)
 
380
  cropped = img_array
381
  bbox = None
382
+
383
  for r in results:
384
  if len(r.boxes.xyxy) == 0:
385
  continue
386
+
387
+ boxes = r.boxes.xyxy.cpu().numpy()
388
+ scores = r.boxes.conf.cpu().numpy()
389
+
390
+ # Pick index of highest confidence
391
+ i = int(scores.argmax())
392
+
393
  x1, y1, x2, y2 = map(int, boxes[i].tolist())
394
  cropped = img_array[y1:y2, x1:x2]
395
+ bbox = {
396
+ "x1": x1,
397
+ "y1": y1,
398
+ "x2": x2,
399
+ "y2": y2,
400
+ "conf": float(scores[i]),
401
+ }
402
+ break # only use first image in batch
403
+
404
  return cropped, bbox
405
 
406
 
407
+
408
  def encode_image_to_data_url(img_array: np.ndarray, format: str = "JPEG") -> str:
409
  """Encode an RGB image array to a data URL suitable for GPT-4o image input."""
410
  pil_img = Image.fromarray(img_array)
 
574
  content_str = getattr(result, "content", str(result))
575
  extracted_obj = parse_extracted_json(content_str)
576
 
 
577
  cropped_bytes = encode_image_to_jpeg_bytes(cropped)
578
+
579
+ # Build storage path with category slug
580
+ category = extracted_obj.get("category")
581
+ def category_to_slug(category: str | None) -> str:
582
+ if not category:
583
+ return "uncategorized"
584
+ return (
585
+ category.strip().lower()
586
+ .replace("&", "and")
587
+ .replace("/", "_")
588
+ .replace(" ", "_")
589
+ .replace("-", "_")
590
+ )
591
+
592
+ category_slug = category_to_slug(category)
593
+ storage_path = f"{user_id}/{category_slug}/{int(time.time()*1000)}_cropped.jpg"
594
+
595
  try:
596
  stored = upload_to_storage(storage_path, cropped_bytes, "image/jpeg")
597
+
598
  except Exception as exc:
599
  from fastapi import HTTPException
600
  raise HTTPException(status_code=502, detail=f"Storage upload failed: {exc}")