nehakothari commited on
Commit
57edf60
·
verified ·
1 Parent(s): 38bc314

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -0
app.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+ import os
4
+ import gradio as gr
5
+ from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
6
+ from qwen_vl_utils import process_vision_info
7
+ import torch
8
+ import pandas as pd
9
+ import pytesseract
10
+ import cv2
11
+ import pymssql
12
+
13
+ # Hardcoded Hugging Face token and SQL server IP address
14
+ SERVER_IP = "35.227.148.156"
15
+
16
+ # Install dependencies in smaller chunks to avoid memory issues
17
+ def install_dependencies():
18
+ dependency_groups = [
19
+ ["pip==23.3.1", "setuptools", "wheel"],
20
+ ["pytesseract"],
21
+ ["torch==2.1.0+cpu", "torchvision==0.16.0+cpu", "torchaudio==2.1.0+cpu"],
22
+ ["transformers==4.38.2", "auto-gptq==0.7.1", "autoawq==0.2.8"],
23
+ ["qwen_vl_utils==0.0.8", "gradio==4.27.0"],
24
+ ["pyodbc", "sqlalchemy", "azure-storage-blob", "pymssql", "pandas", "opencv-python"]
25
+ ]
26
+
27
+ for group in dependency_groups:
28
+ for package in group:
29
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package], stdout=sys.stdout, stderr=sys.stderr)
30
+ print(f"Installed {package}")
31
+
32
+ install_dependencies()
33
+
34
+ # Install system dependencies (executed separately to avoid timeout issues)
35
+ def install_system_dependencies():
36
+ commands = [
37
+ "apt-get update",
38
+ "apt-get install -y unixodbc-dev tesseract-ocr",
39
+ "ACCEPT_EULA=Y apt-get install -y msodbcsql17"
40
+ ]
41
+ for command in commands:
42
+ subprocess.run(command, shell=True, check=True)
43
+ print(f"Executed: {command}")
44
+
45
+ install_system_dependencies()
46
+
47
+ # Initialize model and processor with CPU mode
48
+ model = Qwen2VLForConditionalGeneration.from_pretrained(
49
+ "Qwen/Qwen2-VL-2B-Instruct-AWQ",
50
+ torch_dtype="auto",
51
+ use_auth_token=HUGGINGFACE_API_KEY
52
+ )
53
+
54
+ # Force model to use CPU to avoid memory issues on Hugging Face Spaces
55
+ model.to("cpu")
56
+
57
+ processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct-AWQ", use_auth_token=HUGGINGFACE_API_KEY)
58
+
59
+ pytesseract.pytesseract_cmd = r'/usr/bin/tesseract'
60
+
61
+ # Function to preprocess the image for OCR
62
+ def preprocess_image(image_path):
63
+ image = cv2.imread(image_path)
64
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
65
+ _, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
66
+ return binary
67
+
68
+ # Function to extract text using OCR
69
+ def ocr_extract_text(image_path):
70
+ preprocessed_image = preprocess_image(image_path)
71
+ return pytesseract.image_to_string(preprocessed_image)
72
+
73
+ # Function to process image and extract details
74
+ def process_image(image_path):
75
+ try:
76
+ messages = [{
77
+ "role": "user",
78
+ "content": [
79
+ {"type": "image", "image": image_path},
80
+ {"type": "text", "text": (
81
+ "Extract the following details from the invoice:\n"
82
+ "- 'invoice_number'\n"
83
+ "- 'date'\n"
84
+ "- 'place'\n"
85
+ "- 'amount' (monetary value in the relevant currency)\n"
86
+ "- 'category' (based on the invoice type)"
87
+ )}
88
+ ]
89
+ }]
90
+
91
+ text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
92
+ image_inputs, video_inputs = process_vision_info(messages)
93
+ inputs = processor(text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt")
94
+ inputs = inputs.to(model.device)
95
+
96
+ generated_ids = model.generate(**inputs, max_new_tokens=128)
97
+ output_text = processor.batch_decode(generated_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)
98
+
99
+ return parse_details(output_text[0])
100
+
101
+ except Exception as e:
102
+ print(f"Model failed, falling back to OCR: {e}")
103
+ ocr_text = ocr_extract_text(image_path)
104
+ return parse_details(ocr_text)
105
+
106
+ # Function to parse details from extracted text
107
+ def parse_details(details):
108
+ parsed_data = {
109
+ "Invoice Number": None,
110
+ "Date": None,
111
+ "Place": None,
112
+ "Amount": None,
113
+ "Category": None
114
+ }
115
+
116
+ lines = details.split("\n")
117
+ for line in lines:
118
+ lower_line = line.lower()
119
+ if "invoice" in lower_line:
120
+ parsed_data["Invoice Number"] = line.split(":")[-1].strip()
121
+ elif "date" in lower_line:
122
+ parsed_data["Date"] = line.split(":")[-1].strip()
123
+ elif "place" in lower_line:
124
+ parsed_data["Place"] = line.split(":")[-1].strip()
125
+ elif any(keyword in lower_line for keyword in ["total", "amount", "cost"]):
126
+ parsed_data["Amount"] = line.split(":")[-1].strip()
127
+ else:
128
+ parsed_data["Category"] = "General"
129
+
130
+ return parsed_data
131
+
132
+ # Store extracted data in Azure SQL Database
133
+ def store_to_azure_sql(dataframe):
134
+ conn_str = (
135
+ f"Driver={{ODBC Driver 17 for SQL Server}};"
136
+ f"Server={SERVER_IP};"
137
+ "Database=Invoices;"
138
+ "UID=pio-admin;"
139
+ "PWD=Poctest123#;"
140
+ )
141
+ try:
142
+ with pymssql.connect(SERVER_IP, "pio-admin", "Poctest123#", "Invoices") as conn:
143
+ cursor = conn.cursor()
144
+ create_table_query = """
145
+ IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Invoices' AND xtype='U')
146
+ CREATE TABLE Invoices (
147
+ InvoiceNumber NVARCHAR(255),
148
+ Date NVARCHAR(255),
149
+ Place NVARCHAR(255),
150
+ Amount NVARCHAR(255),
151
+ Category NVARCHAR(255)
152
+ )
153
+ """
154
+ cursor.execute(create_table_query)
155
+
156
+ for _, row in dataframe.iterrows():
157
+ insert_query = """
158
+ INSERT INTO Invoices (InvoiceNumber, Date, Place, Amount, Category)
159
+ VALUES (%s, %s, %s, %s, %s)
160
+ """
161
+ cursor.execute(insert_query, (row['Invoice Number'], row['Date'], row['Place'], row['Amount'], row['Category']))
162
+ conn.commit()
163
+ print("Data successfully stored in Azure SQL Database.")
164
+ except Exception as e:
165
+ print(f"Error storing data to database: {e}")
166
+
167
+ # Gradio interface for invoice processing
168
+ def gradio_interface(image_files):
169
+ results = []
170
+ for image_file in image_files:
171
+ details = process_image(image_file)
172
+ results.append(details)
173
+
174
+ df = pd.DataFrame(results)
175
+ store_to_azure_sql(df)
176
+ return df
177
+
178
+ # Launch Gradio interface
179
+ grpc_interface = gr.Interface(
180
+ fn=gradio_interface,
181
+ inputs=gr.Files(label="Upload Invoice Images"),
182
+ outputs=gr.Dataframe(interactive=True),
183
+ title="Invoice Extraction System",
184
+ )
185
+
186
+ if __name__ == "__main__":
187
+ grpc_interface.launch(share=True)