ashhal commited on
Commit
9052fb4
Β·
verified Β·
1 Parent(s): 723a7cb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -89
app.py CHANGED
@@ -106,100 +106,155 @@ def verify_password(password, hashed):
106
  class ImageProcessor:
107
  """Handles image preprocessing for better OCR results"""
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  @staticmethod
110
  def process_receipt_image(image_file, phone):
111
- """
112
- Complete receipt processing pipeline that handles Gradio file objects
113
- Returns: (success, status_message, extracted_data, image_preview)
114
- """
115
- try:
116
- if not phone:
117
- return False, "❌ Please sign in first", {}, None
118
-
119
- if not image_file:
120
- return False, "❌ No image uploaded", {}, None
121
 
122
- # Debug input type
123
- print(f"\nπŸ“ Input type: {type(image_file)}")
124
-
125
- # Handle different input types
126
- if isinstance(image_file, str):
127
- # Case 1: Direct file path (local testing)
128
- image_path = image_file
129
- elif hasattr(image_file, 'name'):
130
- # Case 2: Gradio NamedString object (Hugging Face Spaces)
131
- image_path = image_file.name
132
- else:
133
- return False, "❌ Unsupported file input type", {}, None
134
 
135
- # Create receipts directory if needed
136
- os.makedirs(RECEIPTS_DIR, exist_ok=True)
137
-
138
- # Generate unique filename
139
- timestamp = int(time.time())
140
- filename = f"receipt_{phone}_{timestamp}{os.path.splitext(image_path)[1]}"
141
- save_path = os.path.join(RECEIPTS_DIR, filename)
142
-
143
- # Copy the uploaded file (works for both Gradio and direct paths)
144
- with open(image_path, 'rb') as src, open(save_path, 'wb') as dst:
145
- dst.write(src.read())
146
-
147
- print(f"πŸ“„ Saved receipt to: {save_path}")
148
-
149
- # Preprocess image
150
- processed_path, preprocessing_info = ImageProcessor.preprocess_receipt_image(save_path)
151
- print(f"πŸ–ΌοΈ Preprocessing: {preprocessing_info}")
152
-
153
- # Extract text using OCR
154
- raw_text, confidence, extracted_data = ocr_service.extract_text_from_receipt(processed_path)
155
- print(f"πŸ” OCR Confidence: {confidence:.1%}")
156
-
157
- # Auto-categorize
158
- if extracted_data.get('merchant'):
159
- suggested_category = db.auto_categorize_receipt(
160
- phone,
161
- extracted_data['merchant'],
162
- extracted_data.get('total_amount', 0)
163
- )
164
- extracted_data['suggested_category'] = suggested_category
165
- print(f"🏷️ Suggested category: {suggested_category}")
166
-
167
- # Prepare receipt data for database
168
- receipt_data = {
169
- 'image_path': save_path,
170
- 'processed_image_path': processed_path,
171
- 'merchant': extracted_data.get('merchant', ''),
172
- 'amount': extracted_data.get('total_amount', 0.0),
173
- 'date': extracted_data.get('date', ''),
174
- 'category': extracted_data.get('suggested_category', 'Miscellaneous'),
175
- 'confidence': confidence,
176
- 'raw_text': raw_text,
177
- 'extracted_data': extracted_data,
178
- 'is_validated': False
179
- }
180
-
181
- # Save to database
182
- receipt_id = db.save_receipt(phone, receipt_data)
183
- extracted_data['receipt_id'] = receipt_id
184
- print(f"πŸ’Ύ Saved to DB with ID: {receipt_id}")
185
-
186
- # Create image preview
187
- try:
188
- image_preview = Image.open(save_path)
189
- image_preview.thumbnail((400, 600)) # Resize for display
 
 
 
 
 
 
 
 
 
 
190
  except Exception as e:
191
- print(f"⚠️ Preview generation failed: {e}")
192
- image_preview = None
193
-
194
- status_msg = f"βœ… Receipt processed! Confidence: {confidence:.1%}"
195
- if confidence < 0.7:
196
- status_msg += " ⚠️ Low confidence - please verify"
197
-
198
- return True, status_msg, extracted_data, image_preview
199
-
200
- except Exception as e:
201
- print(f"❌ Processing error: {traceback.format_exc()}")
202
- return False, f"❌ Processing failed: {str(e)}", {}, None
203
 
204
  @staticmethod
205
  def extract_text_regions(image_path):
 
106
  class ImageProcessor:
107
  """Handles image preprocessing for better OCR results"""
108
 
109
+ @staticmethod
110
+ def preprocess_receipt_image(image_path):
111
+ """
112
+ Preprocess receipt image for optimal OCR
113
+ Returns: processed image path and preprocessing info
114
+ """
115
+ try:
116
+ if not PIL_AVAILABLE:
117
+ return image_path, "No preprocessing - PIL not available"
118
+
119
+ # Load image
120
+ image = Image.open(image_path)
121
+
122
+ # Convert to RGB if needed
123
+ if image.mode != 'RGB':
124
+ image = image.convert('RGB')
125
+
126
+ # Enhance contrast
127
+ enhancer = ImageEnhance.Contrast(image)
128
+ image = enhancer.enhance(1.5)
129
+
130
+ # Enhance sharpness
131
+ enhancer = ImageEnhance.Sharpness(image)
132
+ image = enhancer.enhance(2.0)
133
+
134
+ # Convert to grayscale
135
+ image = image.convert('L')
136
+
137
+ # Apply Gaussian blur to reduce noise
138
+ image = image.filter(ImageFilter.GaussianBlur(radius=0.5))
139
+
140
+ # Convert to numpy array for OpenCV processing
141
+ if 'cv2' in globals() and cv2 is not None:
142
+ img_array = np.array(image)
143
+
144
+ # Apply threshold to get binary image
145
+ _, binary = cv2.threshold(img_array, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
146
+
147
+ # Morphological operations to clean up the image
148
+ kernel = np.ones((1,1), np.uint8)
149
+ binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
150
+
151
+ # Convert back to PIL Image
152
+ image = Image.fromarray(binary)
153
+
154
+ # Save processed image
155
+ processed_path = image_path.replace('.', '_processed.')
156
+ image.save(processed_path)
157
+
158
+ return processed_path, "Enhanced contrast, sharpness, applied thresholding"
159
+
160
+ except Exception as e:
161
+ print(f"Image preprocessing error: {e}")
162
+ return image_path, f"Preprocessing failed: {str(e)}"
163
+
164
  @staticmethod
165
  def process_receipt_image(image_file, phone):
166
+ """
167
+ Complete receipt processing pipeline that handles Gradio file objects
168
+ Returns: (success, status_message, extracted_data, image_preview)
169
+ """
170
+ try:
171
+ if not phone:
172
+ return False, "❌ Please sign in first", {}, None
173
+
174
+ if not image_file:
175
+ return False, "❌ No image uploaded", {}, None
176
 
177
+ # Debug input type
178
+ print(f"\nπŸ“ Input type: {type(image_file)}")
179
+
180
+ # Handle different input types
181
+ if isinstance(image_file, str):
182
+ # Case 1: Direct file path (local testing)
183
+ image_path = image_file
184
+ elif hasattr(image_file, 'name'):
185
+ # Case 2: Gradio NamedString object (Hugging Face Spaces)
186
+ image_path = image_file.name
187
+ else:
188
+ return False, "❌ Unsupported file input type", {}, None
189
 
190
+ # Create receipts directory if needed
191
+ os.makedirs(RECEIPTS_DIR, exist_ok=True)
192
+
193
+ # Generate unique filename
194
+ timestamp = int(time.time())
195
+ filename = f"receipt_{phone}_{timestamp}{os.path.splitext(image_path)[1]}"
196
+ save_path = os.path.join(RECEIPTS_DIR, filename)
197
+
198
+ # Copy the uploaded file (works for both Gradio and direct paths)
199
+ with open(image_path, 'rb') as src, open(save_path, 'wb') as dst:
200
+ dst.write(src.read())
201
+
202
+ print(f"πŸ“„ Saved receipt to: {save_path}")
203
+
204
+ # Preprocess image
205
+ processed_path, preprocessing_info = ImageProcessor.preprocess_receipt_image(save_path)
206
+ print(f"πŸ–ΌοΈ Preprocessing: {preprocessing_info}")
207
+
208
+ # Extract text using OCR
209
+ raw_text, confidence, extracted_data = ocr_service.extract_text_from_receipt(processed_path)
210
+ print(f"πŸ” OCR Confidence: {confidence:.1%}")
211
+
212
+ # Auto-categorize
213
+ if extracted_data.get('merchant'):
214
+ suggested_category = db.auto_categorize_receipt(
215
+ phone,
216
+ extracted_data['merchant'],
217
+ extracted_data.get('total_amount', 0)
218
+ )
219
+ extracted_data['suggested_category'] = suggested_category
220
+ print(f"🏷️ Suggested category: {suggested_category}")
221
+
222
+ # Prepare receipt data for database
223
+ receipt_data = {
224
+ 'image_path': save_path,
225
+ 'processed_image_path': processed_path,
226
+ 'merchant': extracted_data.get('merchant', ''),
227
+ 'amount': extracted_data.get('total_amount', 0.0),
228
+ 'date': extracted_data.get('date', ''),
229
+ 'category': extracted_data.get('suggested_category', 'Miscellaneous'),
230
+ 'confidence': confidence,
231
+ 'raw_text': raw_text,
232
+ 'extracted_data': extracted_data,
233
+ 'is_validated': False
234
+ }
235
+
236
+ # Save to database
237
+ receipt_id = db.save_receipt(phone, receipt_data)
238
+ extracted_data['receipt_id'] = receipt_id
239
+ print(f"πŸ’Ύ Saved to DB with ID: {receipt_id}")
240
+
241
+ # Create image preview
242
+ try:
243
+ image_preview = Image.open(save_path)
244
+ image_preview.thumbnail((400, 600)) # Resize for display
245
+ except Exception as e:
246
+ print(f"⚠️ Preview generation failed: {e}")
247
+ image_preview = None
248
+
249
+ status_msg = f"βœ… Receipt processed! Confidence: {confidence:.1%}"
250
+ if confidence < 0.7:
251
+ status_msg += " ⚠️ Low confidence - please verify"
252
+
253
+ return True, status_msg, extracted_data, image_preview
254
+
255
  except Exception as e:
256
+ print(f"❌ Processing error: {traceback.format_exc()}")
257
+ return False, f"❌ Processing failed: {str(e)}", {}, None
 
 
 
 
 
 
 
 
 
 
258
 
259
  @staticmethod
260
  def extract_text_regions(image_path):