ashhal commited on
Commit
723a7cb
Β·
verified Β·
1 Parent(s): 6c33f0c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -51
app.py CHANGED
@@ -107,59 +107,99 @@ 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 extract_text_regions(image_path):
 
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):