Namra-Satva commited on
Commit
26c450d
·
verified ·
1 Parent(s): 8a1a23f

First Commit

Browse files
Files changed (4) hide show
  1. README.md +10 -10
  2. main.py +25 -0
  3. model_utils.py +62 -0
  4. requirements.txt +7 -0
README.md CHANGED
@@ -1,10 +1,10 @@
1
- ---
2
- title: Invoice Ocr Api
3
- emoji: 😻
4
- colorFrom: gray
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Invoice Ocr Api
3
+ emoji: 😻
4
+ colorFrom: gray
5
+ colorTo: purple
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
main.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile
2
+ from fastapi.responses import JSONResponse
3
+ import shutil
4
+ import os
5
+ from model_utils import extract_invoice_data_from_image
6
+
7
+ app = FastAPI()
8
+
9
+ UPLOAD_DIR = "uploads"
10
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
11
+
12
+ @app.post("/extract-invoice")
13
+ async def extract_invoice(file: UploadFile = File(...)):
14
+ # Save the uploaded image temporarily
15
+ file_location = os.path.join(UPLOAD_DIR, file.filename)
16
+ with open(file_location, "wb") as f:
17
+ shutil.copyfileobj(file.file, f)
18
+
19
+ # Run OCR + detection
20
+ extracted_data = extract_invoice_data_from_image(file_location)
21
+
22
+ # Optionally, clean up the uploaded file
23
+ os.remove(file_location)
24
+
25
+ return JSONResponse(content=extracted_data)
model_utils.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import pytesseract
3
+ import re
4
+ from PIL import Image
5
+ from ultralytics import YOLO
6
+
7
+ # Path to your trained YOLO model
8
+ MODEL_PATH = "yolov8m_invoiceOCR.pt"
9
+
10
+ # YOLO class names (order matters)
11
+ class_names = [
12
+ "Discount_Percentage", "Due_Date", "Email_Client", "Name_Client", "Products",
13
+ "Remise", "Subtotal", "Tax", "Tax_Precentage", "Tel_Client", "billing address",
14
+ "header", "invoice date", "invoice number", "shipping address", "total"
15
+ ]
16
+
17
+ # Load YOLOv8 model
18
+ model = YOLO(MODEL_PATH)
19
+
20
+ def initialize_data_dict():
21
+ return {label: [] if label == "Products" else "" for label in class_names}
22
+
23
+ def parse_products(raw_text):
24
+ structured = []
25
+ lines = raw_text.split('\n')
26
+ for line in lines:
27
+ match = re.match(r"(\d+)\s+(.*)\s+([\d,]+\.\d{2})\s+([\d,]+\.\d{2})", line)
28
+ if match:
29
+ qty, desc, unit_price, amount = match.groups()
30
+ structured.append({
31
+ "qty": qty,
32
+ "description": desc.strip(),
33
+ "unit_price": unit_price,
34
+ "amount": amount
35
+ })
36
+ elif line.strip():
37
+ structured.append({"raw": line.strip()})
38
+ return structured
39
+
40
+ def extract_invoice_data_from_image(image_path: str):
41
+ image_bgr = cv2.imread(image_path)
42
+ image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
43
+ pil_img = Image.fromarray(image_rgb)
44
+
45
+ results = model(image_path)[0]
46
+ data = initialize_data_dict()
47
+
48
+ for box in results.boxes:
49
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
50
+ cls_id = int(box.cls[0])
51
+ label = class_names[cls_id]
52
+
53
+ cropped_img = pil_img.crop((x1, y1, x2, y2))
54
+ extracted_text = pytesseract.image_to_string(cropped_img, config='--psm 6').strip()
55
+
56
+ if label == "Products" and extracted_text:
57
+ structured_products = parse_products(extracted_text)
58
+ data["Products"].extend(structured_products)
59
+ elif extracted_text:
60
+ data[label] = extracted_text
61
+
62
+ return data
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ opencv-python
4
+ pytesseract
5
+ torch
6
+ Pillow
7
+ ultralytics