ShutterStack commited on
Commit
729a21e
·
verified ·
1 Parent(s): eff69ae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +298 -336
app.py CHANGED
@@ -1,336 +1,298 @@
1
- from flask import Flask, request, jsonify, render_template, send_file
2
- import os
3
- from ultralytics import YOLO
4
- from easyocr import Reader
5
- import zipfile
6
- import pandas as pd
7
- import cv2
8
- from fuzzywuzzy import fuzz, process
9
- import re
10
- import numpy as np
11
- import json
12
- import sqlite3
13
-
14
- app = Flask(__name__)
15
- app.config['UPLOAD_FOLDER'] = 'uploads/'
16
- app.config['ALLOWED_EXTENSIONS'] = {'zip', 'xlsx'}
17
- app.config['RESULTS_FOLDER'] = 'results/'
18
- app.config['DATABASE'] = 'results_ack.db'
19
-
20
- classifier = YOLO("./models/classification.pt")
21
- detector = YOLO("./models/detection.pt")
22
- reader = Reader(['en'])
23
-
24
- def process_image(image_path):
25
- if classifier.predict(image_path)[0].probs.numpy().top1 == 0:
26
- fields = detector(image_path)
27
- image = cv2.imread(image_path)
28
- extracted_data = {}
29
- for field in fields[0].boxes.data.tolist():
30
- x1, y1, x2, y2, confidence, class_id = map(int, field[:6])
31
- field_class = detector.names[class_id]
32
- cropped_roi = image[y1:y2, x1:x2]
33
- gray_roi = cv2.cvtColor(cropped_roi, cv2.COLOR_BGR2GRAY)
34
- text = reader.readtext(gray_roi, detail=0)
35
- extracted_data[field_class] = ' '.join(text)
36
- return extracted_data
37
- return None
38
-
39
- # Helper Functions
40
- def normalize_text(text):
41
- if not text:
42
- return "text empty"
43
- text = re.sub(r"[^\w\s]", "", text)
44
- return " ".join(text.split()).lower()
45
-
46
- def calculate_match_score(input_value, extracted_value):
47
- if pd.isna(input_value) or pd.isna(extracted_value):
48
- return 0
49
- return fuzz.ratio(str(input_value), str(extracted_value))
50
-
51
- def name_match(input_name, extracted_name):
52
- if extracted_name is None:
53
- return False
54
- input_name = normalize_text(input_name)
55
- extracted_name = normalize_text(extracted_name)
56
-
57
- if input_name == extracted_name:
58
- return True
59
-
60
- input_parts = input_name.split()
61
- extracted_parts = extracted_name.split()
62
-
63
- if sorted(input_parts) == sorted(extracted_parts):
64
- return True
65
-
66
- if len(input_parts) == 2 and len(extracted_parts) == 3:
67
- if input_parts[0] == extracted_parts[0] and input_parts[1] == extracted_parts[2]:
68
- return True
69
- if len(input_parts) == 3 and len(extracted_parts) == 2:
70
- if extracted_parts[0] == input_parts[0] and extracted_parts[1] == input_parts[2]:
71
- return True
72
-
73
- for part in input_parts:
74
- if part not in extracted_parts:
75
- return False
76
- return True
77
-
78
- def address_match(input_address, extracted_address):
79
- print(input_address, extracted_address)
80
- if input_address is None or extracted_address is None:
81
- return False, 0.0, {}
82
-
83
- # Handle input_address if it's a Series
84
- if isinstance(input_address, pd.Series):
85
- input_address = input_address.to_dict()
86
-
87
- print(extracted_address)
88
- extracted_address = normalize_text(extracted_address)
89
- final_score = 0
90
- print(extracted_address)
91
- weights = {
92
- "State": 0.2,
93
- "Landmark": 0.2,
94
- "Premise Building Name": 0.2,
95
- "City":0.2,
96
- "Street Road Name":0.1,
97
- "Floor Number": 0.05,
98
- "House Flat Number": 0.05
99
- }
100
- tokens = extracted_address.split(" ")
101
- # Component matching logic
102
- for field, weight in weights.items():
103
- input_value = input_address.get(field, "")
104
- match_score = fuzz.token_set_ratio(normalize_text(input_value), extracted_address) if input_value else 0
105
- input_address[field + " Match Score"] = match_score
106
- final_score += match_score * weight
107
- pincode_score = process.extractOne(input_address.get("PINCODE"), tokens)[1]
108
- input_address['PINCODE Match Score'] = pincode_score
109
- pincode_matched = True if input_address['PINCODE Match Score'] == 100 else False
110
-
111
- return final_score >= 70 and pincode_matched, final_score, input_address
112
-
113
- def compare_data(input_data, json_data):
114
- excel_data = input_data.copy()
115
- for idx, row in excel_data.iterrows():
116
- serial_no = row.get("SrNo")
117
- uid = row.get("UID")
118
- extracted = json_data.get(serial_no)
119
-
120
- if extracted:
121
- extracted_uid = extracted.get("uid", "").replace(" ", "")
122
- extracted_name = extracted.get("name", "")
123
- extracted_address = extracted.get("address", "")
124
- row['Extracted UID'] = extracted_uid
125
- row['Extracted Name'] = extracted_name
126
- row['Extracted Address'] = extracted_address
127
- # UID Match
128
- uid_match = uid == extracted_uid
129
- uid_score = 100 if uid_match else 0
130
- row['UID Match Score'] = uid_score
131
-
132
- # Name Match
133
- name_match_result = name_match(row.get("Name"), extracted_name)
134
- name_score = calculate_match_score(row.get("Name"), extracted_name)
135
- row['Name Match Score'] = name_score
136
- row['Name Match Percentage'] = name_score
137
-
138
- # Address Match
139
- address_match_result, address_score, partial_scores = address_match(row, extracted_address)
140
- if partial_scores:
141
- row['House Flat Number Match Score'] = partial_scores['House Flat Number Match Score']
142
- row['Street Road Name Match Score'] = partial_scores['Street Road Name Match Score']
143
- row['City Match Score'] = partial_scores['City Match Score']
144
- row['Floor Number Match Score'] = partial_scores['Floor Number Match Score']
145
- row['Premise Building Name Match Score'] = partial_scores['Premise Building Name Match Score']
146
- row['Landmark Match Score'] = partial_scores['Landmark Match Score']
147
- row['State Match Score'] = partial_scores['State Match Score']
148
- row['Final Address Match'] = address_match_result
149
- row['Final Address Match Score'] = address_score
150
- row['PINCODE Match Score'] = partial_scores['PINCODE Match Score']
151
-
152
- # Final Match
153
- overall_match = uid_match and name_match_result and address_match_result
154
-
155
- row['Overall Match'] = overall_match
156
-
157
- if overall_match:
158
- row['Final Remarks'] = "All matched"
159
- elif not uid_match:
160
- row['Final Remarks'] = "UID mismatch"
161
- elif not name_match_result:
162
- row['Final Remarks'] = "Name mismatch"
163
- elif not address_match_result:
164
- row['Final Remarks'] = "Address mismatch"
165
- else:
166
- if extracted_address is None:
167
- row['Final Remarks'] = "Address missing in aadhar"
168
- elif extracted_name is None:
169
- row['Final Remarks'] = "Name missing in aadhar"
170
- else:
171
- row['Final Remarks'] = "Non Aadhar"
172
-
173
- row["Document Type"] = "Aadhaar" if overall_match else "Non-Aadhaar"
174
- else:
175
- row.replace(float('nan'), 0)
176
- row['Final Remarks'] = "Non Aadhar"
177
- row['Document Type'] = "Non Aadhar"
178
- excel_data.loc[idx] = row
179
- return excel_data
180
-
181
- def create_visualizations(comparison_results):
182
- visualization_data = {}
183
-
184
- # TODO: Implement your visualization logic here
185
-
186
- # Example: Frequency of 'Final Remarks' (for a bar chart)
187
- visualization_data['final_remarks_frequency'] = {
188
- 'labels': comparison_results['Final Remarks'].value_counts().index.tolist(),
189
- 'values': comparison_results['Final Remarks'].value_counts().values.tolist()
190
- }
191
-
192
- # 2. Document Type Proportion (Pie Chart)
193
- visualization_data['document_type_proportion'] = {
194
- 'labels': comparison_results['Document Type'].value_counts().index.tolist(),
195
- 'values': comparison_results['Document Type'].value_counts().values.tolist()
196
- }
197
-
198
- # 3. Accepted vs. Rejected Proportion (Pie Chart)
199
- visualization_data['accepted_rejected_proportion'] = {
200
- 'labels': comparison_results['Accepted/Rejected'].value_counts().index.tolist(),
201
- 'values': comparison_results['Accepted/Rejected'].value_counts().values.tolist()
202
- }
203
-
204
- # 4. UID Match Score Distribution (Histogram)
205
- visualization_data['uid_match_score_distribution'] = {
206
- 'values': comparison_results['UID Match Score'].tolist()
207
- }
208
-
209
- # 5. Name Match Score Distribution (Histogram)
210
- visualization_data['name_match_score_distribution'] = {
211
- 'values': comparison_results['Name Match Score'].tolist()
212
- }
213
-
214
- # 6. Final Address Match Score Distribution (Histogram)
215
- visualization_data['address_match_score_distribution'] = {
216
- 'values': comparison_results['Final Address Match Score'].tolist()
217
- }
218
-
219
- return visualization_data
220
-
221
- def create_database_and_table():
222
- """Creates the database and table if they don't exist."""
223
- conn = sqlite3.connect(app.config['DATABASE'])
224
- cursor = conn.cursor()
225
-
226
- cursor.execute('''
227
- CREATE TABLE IF NOT EXISTS results (
228
- id INTEGER PRIMARY KEY AUTOINCREMENT,
229
- SrNo TEXT,
230
- DocumentType TEXT,
231
- AcceptedRejected TEXT,
232
- FinalRemarks TEXT
233
- )
234
- ''')
235
- conn.commit()
236
- conn.close()
237
-
238
- def save_results_to_database(results):
239
- """Saves the provided results to the SQLite database."""
240
- conn = sqlite3.connect(app.config['DATABASE'])
241
- cursor = conn.cursor()
242
-
243
- for result in results:
244
- cursor.execute('''
245
- INSERT INTO results (SrNo, DocumentType, AcceptedRejected, FinalRemarks)
246
- VALUES (?, ?, ?, ?)
247
- ''', (
248
- result.get('SrNo', ''),
249
- result.get('Document Type', ''),
250
- result.get('Accepted/Rejected', ''),
251
- result.get('Final Remarks', '')
252
- ))
253
-
254
- conn.commit()
255
- conn.close()
256
-
257
-
258
-
259
- @app.route('/download', methods=['GET'])
260
- def download_results():
261
- file_path = os.path.join(app.config['RESULTS_FOLDER'], 'results.xlsx')
262
- return send_file(file_path, as_attachment=True)
263
-
264
- @app.route('/')
265
- def home():
266
- return render_template('index.html')
267
-
268
- @app.route('/services', methods=['GET'])
269
- def services():
270
- return render_template('services.html')
271
-
272
- @app.route('/about', methods=['GET'])
273
- def about():
274
- return render_template('about.html')
275
-
276
- @app.route('/contact', methods=['GET'])
277
- def contact():
278
- return render_template('contact.html')
279
-
280
- @app.route('/upload', methods=['POST'])
281
- def upload_files():
282
- if 'zipfile' in request.files and 'excelfile' in request.files:
283
- zip_file = request.files['zipfile']
284
- excel_file = request.files['excelfile']
285
-
286
- # Save files
287
- zip_path = os.path.join(app.config['UPLOAD_FOLDER'], zip_file.filename)
288
- excel_path = os.path.join(app.config['UPLOAD_FOLDER'], excel_file.filename)
289
- zip_file.save(zip_path)
290
- excel_file.save(excel_path)
291
-
292
- # Unzip and process images
293
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
294
- zip_ref.extractall(app.config['UPLOAD_FOLDER'])
295
-
296
- image_paths = [os.path.join(app.config['UPLOAD_FOLDER'], f) for f in os.listdir(app.config['UPLOAD_FOLDER']) if f.endswith(('.jpg', '.png'))]
297
- processed_results = {}
298
-
299
- for image_path in image_paths:
300
- file_name = os.path.basename(image_path)
301
- key = file_name.split('.')[0][:3]
302
- if key not in processed_results: # Check if key already exists
303
- extracted_data = process_image(image_path)
304
- if extracted_data:
305
- processed_results[key] = extracted_data
306
-
307
- # Read Excel and compare data
308
- df = pd.read_excel(excel_path)
309
- df = df.astype('str')
310
- comparison_results = compare_data(df, processed_results)
311
- comparison_results['Accepted/Rejected'] = np.where(comparison_results['Final Remarks'] == 'All matched', 'Accepted', 'Rejected')
312
-
313
- # Save results to a new Excel file
314
- results_df = pd.DataFrame(comparison_results)
315
- os.makedirs(app.config['RESULTS_FOLDER'], exist_ok=True)
316
- results_file_path = os.path.join(app.config['RESULTS_FOLDER'], 'results.xlsx')
317
- results_df.to_excel(results_file_path, index=False)
318
-
319
- visualization_data = create_visualizations(comparison_results)
320
-
321
- create_database_and_table() # Ensure database and table exist
322
- save_results_to_database(comparison_results[
323
- ['SrNo', 'Document Type', 'Accepted/Rejected', 'Final Remarks']
324
- ].to_dict(orient='records'))
325
-
326
- return jsonify({"message": "Files processed successfully!",
327
- "results": comparison_results[
328
- ['SrNo', 'Document Type', 'Accepted/Rejected', 'Final Remarks']
329
- ].to_dict(orient='records'),
330
- "visualization_data": visualization_data})
331
-
332
- return jsonify({"error": "Both files are required."}), 400
333
-
334
- if __name__ == '__main__':
335
- # Configure HTTPS with self-signed certificate
336
- app.run(ssl_context=('cert.pem', 'key.pem'), debug=True)
 
1
+ from flask import Flask, request, jsonify, render_template, send_file
2
+ import os
3
+ from ultralytics import YOLO
4
+ from easyocr import Reader
5
+ import zipfile
6
+ import pandas as pd
7
+ import cv2
8
+ from fuzzywuzzy import fuzz, process
9
+ import re
10
+ import numpy as np
11
+ import json
12
+ import sqlite3
13
+
14
+ app = Flask(__name__)
15
+ app.config['UPLOAD_FOLDER'] = 'uploads/'
16
+ app.config['ALLOWED_EXTENSIONS'] = {'zip', 'xlsx'}
17
+ app.config['RESULTS_FOLDER'] = 'results/'
18
+
19
+ classifier = YOLO("./models/classification.pt")
20
+ detector = YOLO("./models/detection.pt")
21
+ reader = Reader(['en'])
22
+
23
+ def process_image(image_path):
24
+ if classifier.predict(image_path)[0].probs.numpy().top1 == 0:
25
+ fields = detector(image_path)
26
+ image = cv2.imread(image_path)
27
+ extracted_data = {}
28
+ for field in fields[0].boxes.data.tolist():
29
+ x1, y1, x2, y2, confidence, class_id = map(int, field[:6])
30
+ field_class = detector.names[class_id]
31
+ cropped_roi = image[y1:y2, x1:x2]
32
+ gray_roi = cv2.cvtColor(cropped_roi, cv2.COLOR_BGR2GRAY)
33
+ text = reader.readtext(gray_roi, detail=0)
34
+ extracted_data[field_class] = ' '.join(text)
35
+ return extracted_data
36
+ return None
37
+
38
+ # Helper Functions
39
+ def normalize_text(text):
40
+ if not text:
41
+ return "text empty"
42
+ text = re.sub(r"[^\w\s]", "", text)
43
+ return " ".join(text.split()).lower()
44
+
45
+ def calculate_match_score(input_value, extracted_value):
46
+ if pd.isna(input_value) or pd.isna(extracted_value):
47
+ return 0
48
+ return fuzz.ratio(str(input_value), str(extracted_value))
49
+
50
+ def name_match(input_name, extracted_name):
51
+ if extracted_name is None:
52
+ return False
53
+ input_name = normalize_text(input_name)
54
+ extracted_name = normalize_text(extracted_name)
55
+
56
+ if input_name == extracted_name:
57
+ return True
58
+
59
+ input_parts = input_name.split()
60
+ extracted_parts = extracted_name.split()
61
+
62
+ if sorted(input_parts) == sorted(extracted_parts):
63
+ return True
64
+
65
+ if len(input_parts) == 2 and len(extracted_parts) == 3:
66
+ if input_parts[0] == extracted_parts[0] and input_parts[1] == extracted_parts[2]:
67
+ return True
68
+ if len(input_parts) == 3 and len(extracted_parts) == 2:
69
+ if extracted_parts[0] == input_parts[0] and extracted_parts[1] == input_parts[2]:
70
+ return True
71
+
72
+ for part in input_parts:
73
+ if part not in extracted_parts:
74
+ return False
75
+ return True
76
+
77
+ def address_match(input_address, extracted_address):
78
+ print(input_address, extracted_address)
79
+ if input_address is None or extracted_address is None:
80
+ return False, 0.0, {}
81
+
82
+ # Handle input_address if it's a Series
83
+ if isinstance(input_address, pd.Series):
84
+ input_address = input_address.to_dict()
85
+
86
+ print(extracted_address)
87
+ extracted_address = normalize_text(extracted_address)
88
+ final_score = 0
89
+ print(extracted_address)
90
+ weights = {
91
+ "State": 0.2,
92
+ "Landmark": 0.2,
93
+ "Premise Building Name": 0.2,
94
+ "City":0.2,
95
+ "Street Road Name":0.1,
96
+ "Floor Number": 0.05,
97
+ "House Flat Number": 0.05
98
+ }
99
+ tokens = extracted_address.split(" ")
100
+ # Component matching logic
101
+ for field, weight in weights.items():
102
+ input_value = input_address.get(field, "")
103
+ match_score = fuzz.token_set_ratio(normalize_text(input_value), extracted_address) if input_value else 0
104
+ input_address[field + " Match Score"] = match_score
105
+ final_score += match_score * weight
106
+ pincode_score = process.extractOne(input_address.get("PINCODE"), tokens)[1]
107
+ input_address['PINCODE Match Score'] = pincode_score
108
+ pincode_matched = True if input_address['PINCODE Match Score'] == 100 else False
109
+
110
+ return final_score >= 70 and pincode_matched, final_score, input_address
111
+
112
+ def compare_data(input_data, json_data):
113
+ excel_data = input_data.copy()
114
+ for idx, row in excel_data.iterrows():
115
+ serial_no = row.get("SrNo")
116
+ uid = row.get("UID")
117
+ extracted = json_data.get(serial_no)
118
+
119
+ if extracted:
120
+ extracted_uid = extracted.get("uid", "").replace(" ", "")
121
+ extracted_name = extracted.get("name", "")
122
+ extracted_address = extracted.get("address", "")
123
+ row['Extracted UID'] = extracted_uid
124
+ row['Extracted Name'] = extracted_name
125
+ row['Extracted Address'] = extracted_address
126
+ # UID Match
127
+ uid_match = uid == extracted_uid
128
+ uid_score = 100 if uid_match else 0
129
+ row['UID Match Score'] = uid_score
130
+
131
+ # Name Match
132
+ name_match_result = name_match(row.get("Name"), extracted_name)
133
+ name_score = calculate_match_score(row.get("Name"), extracted_name)
134
+ row['Name Match Score'] = name_score
135
+ row['Name Match Percentage'] = name_score
136
+
137
+ # Address Match
138
+ address_match_result, address_score, partial_scores = address_match(row, extracted_address)
139
+ if partial_scores:
140
+ row['House Flat Number Match Score'] = partial_scores['House Flat Number Match Score']
141
+ row['Street Road Name Match Score'] = partial_scores['Street Road Name Match Score']
142
+ row['City Match Score'] = partial_scores['City Match Score']
143
+ row['Floor Number Match Score'] = partial_scores['Floor Number Match Score']
144
+ row['Premise Building Name Match Score'] = partial_scores['Premise Building Name Match Score']
145
+ row['Landmark Match Score'] = partial_scores['Landmark Match Score']
146
+ row['State Match Score'] = partial_scores['State Match Score']
147
+ row['Final Address Match'] = address_match_result
148
+ row['Final Address Match Score'] = address_score
149
+ row['PINCODE Match Score'] = partial_scores['PINCODE Match Score']
150
+
151
+ # Final Match
152
+ overall_match = uid_match and name_match_result and address_match_result
153
+
154
+ row['Overall Match'] = overall_match
155
+
156
+ if overall_match:
157
+ row['Final Remarks'] = "All matched"
158
+ elif not uid_match:
159
+ row['Final Remarks'] = "UID mismatch"
160
+ elif not name_match_result:
161
+ row['Final Remarks'] = "Name mismatch"
162
+ elif not address_match_result:
163
+ row['Final Remarks'] = "Address mismatch"
164
+ else:
165
+ if extracted_address is None:
166
+ row['Final Remarks'] = "Address missing in aadhar"
167
+ elif extracted_name is None:
168
+ row['Final Remarks'] = "Name missing in aadhar"
169
+ else:
170
+ row['Final Remarks'] = "Non Aadhar"
171
+
172
+ row["Document Type"] = "Aadhaar" if overall_match else "Non-Aadhaar"
173
+ else:
174
+ row.replace(float('nan'), 0)
175
+ row['Final Remarks'] = "Non Aadhar"
176
+ row['Document Type'] = "Non Aadhar"
177
+ excel_data.loc[idx] = row
178
+ return excel_data
179
+
180
+ def create_visualizations(comparison_results):
181
+ visualization_data = {}
182
+
183
+ # TODO: Implement your visualization logic here
184
+
185
+ # Example: Frequency of 'Final Remarks' (for a bar chart)
186
+ visualization_data['final_remarks_frequency'] = {
187
+ 'labels': comparison_results['Final Remarks'].value_counts().index.tolist(),
188
+ 'values': comparison_results['Final Remarks'].value_counts().values.tolist()
189
+ }
190
+
191
+ # 2. Document Type Proportion (Pie Chart)
192
+ visualization_data['document_type_proportion'] = {
193
+ 'labels': comparison_results['Document Type'].value_counts().index.tolist(),
194
+ 'values': comparison_results['Document Type'].value_counts().values.tolist()
195
+ }
196
+
197
+ # 3. Accepted vs. Rejected Proportion (Pie Chart)
198
+ visualization_data['accepted_rejected_proportion'] = {
199
+ 'labels': comparison_results['Accepted/Rejected'].value_counts().index.tolist(),
200
+ 'values': comparison_results['Accepted/Rejected'].value_counts().values.tolist()
201
+ }
202
+
203
+ # 4. UID Match Score Distribution (Histogram)
204
+ visualization_data['uid_match_score_distribution'] = {
205
+ 'values': comparison_results['UID Match Score'].tolist()
206
+ }
207
+
208
+ # 5. Name Match Score Distribution (Histogram)
209
+ visualization_data['name_match_score_distribution'] = {
210
+ 'values': comparison_results['Name Match Score'].tolist()
211
+ }
212
+
213
+ # 6. Final Address Match Score Distribution (Histogram)
214
+ visualization_data['address_match_score_distribution'] = {
215
+ 'values': comparison_results['Final Address Match Score'].tolist()
216
+ }
217
+
218
+ return visualization_data
219
+
220
+
221
+ @app.route('/download', methods=['GET'])
222
+ def download_results():
223
+ file_path = os.path.join(app.config['RESULTS_FOLDER'], 'results.xlsx')
224
+ return send_file(file_path, as_attachment=True)
225
+
226
+ @app.route('/')
227
+ def home():
228
+ return render_template('index.html')
229
+
230
+ @app.route('/services', methods=['GET'])
231
+ def services():
232
+ return render_template('services.html')
233
+
234
+ @app.route('/about', methods=['GET'])
235
+ def about():
236
+ return render_template('about.html')
237
+
238
+ @app.route('/contact', methods=['GET'])
239
+ def contact():
240
+ return render_template('contact.html')
241
+
242
+ @app.route('/upload', methods=['POST'])
243
+ def upload_files():
244
+ if 'zipfile' in request.files and 'excelfile' in request.files:
245
+ zip_file = request.files['zipfile']
246
+ excel_file = request.files['excelfile']
247
+
248
+ # Save files
249
+ zip_path = os.path.join(app.config['UPLOAD_FOLDER'], zip_file.filename)
250
+ excel_path = os.path.join(app.config['UPLOAD_FOLDER'], excel_file.filename)
251
+ zip_file.save(zip_path)
252
+ excel_file.save(excel_path)
253
+
254
+ # Unzip and process images
255
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
256
+ zip_ref.extractall(app.config['UPLOAD_FOLDER'])
257
+
258
+ image_paths = [os.path.join(app.config['UPLOAD_FOLDER'], f) for f in os.listdir(app.config['UPLOAD_FOLDER']) if f.endswith(('.jpg', '.png'))]
259
+ processed_results = {}
260
+
261
+ for image_path in image_paths:
262
+ file_name = os.path.basename(image_path)
263
+ key = file_name.split('.')[0][:3]
264
+ if key not in processed_results: # Check if key already exists
265
+ extracted_data = process_image(image_path)
266
+ if extracted_data:
267
+ processed_results[key] = extracted_data
268
+
269
+ # Read Excel and compare data
270
+ df = pd.read_excel(excel_path)
271
+ df = df.astype('str')
272
+ comparison_results = compare_data(df, processed_results)
273
+ comparison_results['Accepted/Rejected'] = np.where(comparison_results['Final Remarks'] == 'All matched', 'Accepted', 'Rejected')
274
+
275
+ # Save results to a new Excel file
276
+ results_df = pd.DataFrame(comparison_results)
277
+ os.makedirs(app.config['RESULTS_FOLDER'], exist_ok=True)
278
+ results_file_path = os.path.join(app.config['RESULTS_FOLDER'], 'results.xlsx')
279
+ results_df.to_excel(results_file_path, index=False)
280
+
281
+ visualization_data = create_visualizations(comparison_results)
282
+
283
+ create_database_and_table() # Ensure database and table exist
284
+ save_results_to_database(comparison_results[
285
+ ['SrNo', 'Document Type', 'Accepted/Rejected', 'Final Remarks']
286
+ ].to_dict(orient='records'))
287
+
288
+ return jsonify({"message": "Files processed successfully!",
289
+ "results": comparison_results[
290
+ ['SrNo', 'Document Type', 'Accepted/Rejected', 'Final Remarks']
291
+ ].to_dict(orient='records'),
292
+ "visualization_data": visualization_data})
293
+
294
+ return jsonify({"error": "Both files are required."}), 400
295
+
296
+ if __name__ == '__main__':
297
+ # Configure HTTPS with self-signed certificate
298
+ app.run(debug=True)