harshvisualz commited on
Commit
1f215d0
·
1 Parent(s): 9de1e72

Add application file

Browse files
Files changed (3) hide show
  1. Dockerfile +31 -0
  2. app.py +136 -0
  3. requirements.txt +10 -0
Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official python slim image
2
+ FROM python:3.10-slim
3
+
4
+ WORKDIR /app
5
+
6
+ # Install system dependencies
7
+ RUN apt-get update && apt-get install -y \
8
+ build-essential \
9
+ libgl1-mesa-glx \
10
+ libglib2.0-0 \
11
+ libsm6 \
12
+ libxext6 \
13
+ libxrender-dev \
14
+ ffmpeg \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ # Copy requirements.txt and install Python deps
18
+ COPY requirements.txt .
19
+ RUN pip install --no-cache-dir -r requirements.txt
20
+
21
+ # Copy app
22
+ COPY app.py .
23
+
24
+ # Create uploads folder
25
+ RUN mkdir uploads
26
+
27
+ # Expose port (Hugging Face uses 7860 by default, but FastAPI typically uses 8000)
28
+ EXPOSE 8000
29
+
30
+ # Use command to run FastAPI with uvicorn on 0.0.0.0 to accept external connections
31
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import cv2
4
+ import numpy as np
5
+ import matplotlib.pyplot as plt
6
+ import pandas as pd
7
+ from paddleocr import PaddleOCR
8
+ from fastapi import FastAPI, UploadFile, File
9
+ from fastapi.responses import FileResponse, JSONResponse
10
+
11
+ from fastapi.middleware.cors import CORSMiddleware
12
+
13
+ app = FastAPI()
14
+
15
+ origins = [
16
+ "http://localhost.tiangolo.com",
17
+ "https://localhost.tiangolo.com",
18
+ "http://localhost",
19
+ "http://localhost:8080",
20
+ ]
21
+
22
+ app.add_middleware(
23
+ CORSMiddleware,
24
+ allow_origins=['*'],
25
+ allow_credentials=True,
26
+ allow_methods=["*"],
27
+ allow_headers=["*"],
28
+ )
29
+
30
+ # Initialize PaddleOCR
31
+ # ocr = PaddleOCR(use_angle_cls=True, lang="en", det_db_box_thresh=0.5)
32
+
33
+ @app.get("/")
34
+ def read_root():
35
+ return JSONResponse({
36
+ "message": "Hello World"
37
+ })
38
+
39
+ # Load Image
40
+ @app.post("/process_image")
41
+ def load_image(file: UploadFile = File(...)):
42
+ ocr = PaddleOCR(use_angle_cls=True, lang='en')
43
+ image_path = f"uploads/{file.filename}"
44
+ os.makedirs("uploads", exist_ok=True)
45
+
46
+ with open(image_path, "wb") as f:
47
+ shutil.copyfileobj(file.file, f)
48
+
49
+ image = cv2.imread(image_path)
50
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
51
+ height, width, channels = image.shape
52
+
53
+ # OCR Processing
54
+ ocr_results = ocr.ocr(image_path)
55
+ print(ocr_results)
56
+
57
+ extracted_text = []
58
+ page = ocr_results[0]
59
+ for block in page:
60
+ print(block)
61
+ # Lists of recognized texts and their bounding boxes
62
+ texts = page['rec_texts']
63
+ boxes = page['dt_polys']
64
+ scores = page['rec_scores']
65
+ print(texts)
66
+
67
+ # Zip them together
68
+ text_and_boxes = list(zip(texts, boxes, scores))
69
+ final_text = list(zip(texts, scores))
70
+
71
+ # Display all results
72
+ for text, box, score in text_and_boxes:
73
+ print(f"Text: {text}")
74
+ print(f"Bounding Box: {box.tolist()}") # Convert numpy array to regular list
75
+ print(f"Score: {score}")
76
+ print("---")
77
+ extracted_text.append((text, score))
78
+
79
+
80
+ # Print Extracted Text
81
+ print("🔹 Extracted Text from Invoice:")
82
+ for text, score in extracted_text:
83
+ print(f"{text} (Confidence: {score:.2f})")
84
+
85
+ # Create a simple dataframe from all OCR text
86
+ all_text = [text for text, _ in extracted_text]
87
+ print("\n🔹 Creating a simple data structure from all OCR text")
88
+ df = pd.DataFrame({'text': all_text})
89
+ print(df.head())
90
+ df.to_csv("invoice_extracted_text.csv", index=False)
91
+
92
+ # Display Image with OCR Text Overlay
93
+ plt.figure(figsize=(10, 10))
94
+ plt.imshow(image)
95
+
96
+ # Draw bounding boxes and text annotations
97
+ for text, box, score in text_and_boxes:
98
+
99
+ # y_offset = int(0.03 * height) # 5% downward shift
100
+ y_offset = 0
101
+ print(height)
102
+ corrected_box = [(x, y + y_offset) for (x, y) in box]
103
+
104
+ # Draw bounding box
105
+ plt.plot(
106
+ [corrected_box[0][0], corrected_box[1][0], corrected_box[2][0], corrected_box[3][0], corrected_box[0][0]],
107
+ [corrected_box[0][1], corrected_box[1][1], corrected_box[2][1], corrected_box[3][1], corrected_box[0][1]], 'r-'
108
+ )
109
+
110
+ # Add text annotation
111
+ csfont = {'fontname': 'Poppins'}
112
+ plt.text(corrected_box[0][0], corrected_box[0][1], text, color='blue', fontsize=8, **csfont)
113
+
114
+ plt.axis("off")
115
+ plt.tight_layout(pad=2.0)
116
+ plt.savefig(f"uploads/result.png", bbox_inches='tight')
117
+ plt.close()
118
+
119
+ if os.path.exists(image_path):
120
+ os.remove(image_path)
121
+
122
+ return JSONResponse({
123
+ "message": "Image processed successfully",
124
+ "image_path": "result.png",
125
+ "extracted_text": final_text
126
+ })
127
+
128
+ @app.get("/get_image")
129
+ def get_image(input_path: str):
130
+ if not os.path.exists(f"uploads/{input_path}"):
131
+ return JSONResponse({
132
+ "message": "Image not found"
133
+ })
134
+ return FileResponse(f"uploads/{input_path}")
135
+
136
+ print("\n🔹 Processing complete! Annotated image and extracted data saved.")
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn==0.24.0
3
+ python-multipart==0.0.6
4
+ paddleocr==2.7.0
5
+ opencv-python-headless==4.8.1.78
6
+ numpy==1.26.2
7
+ matplotlib==3.8.2
8
+ pandas==2.1.3
9
+ Pillow==10.1.0
10
+ paddlepaddle==2.6.2