devZenaight commited on
Commit
435accf
·
1 Parent(s): 63f1f4e
Files changed (1) hide show
  1. app.py +36 -53
app.py CHANGED
@@ -52,49 +52,35 @@ llm_vision = ChatOpenAI(
52
  )
53
 
54
  # Define the prompt for categorization
55
- text_prompt = ChatPromptTemplate.from_template("""
56
- You are an expert at analyzing receipt text extracted with OCR.
57
- The text may contain noise or extra characters, but focus only on useful parts.
58
 
59
  Rules:
60
- 1. **Venue**:
61
- - This is the store/restaurant/tuck shop/retailer where the receipt comes from.
62
- - It is usually near the top of the receipt (sometimes next to a logo or under "Shop/Store/Restaurant").
63
- - If multiple candidates appear, pick the most likely actual business name (ignore words like "Customer Copy", "Approved", "MasterCard").
64
- - If both a brand name and location/branch are present, include both (e.g. "Checkers - Brooklyn Mall").
65
- - Ignore banks, payment processors, or card brands (e.g., "Nedbank", "FNB", "MasterCard", "Visa") unless they are the ONLY candidate.
66
- - If uncertain, check for context clues like items, meals, or store names to identify the real merchant.
67
- - If you are not confident, return `null`.
68
-
69
- 2. **Date**:
70
- - Look for patterns like `DD-MM-YY`, `YYYY-MM-DD`, `DD/MM/YYYY`, or combined with time (e.g., `2025-09-15 14:23`).
71
- - If only time is found without a date, return `null`.
72
-
73
- 3. **Total**:
74
- - Find the final purchase amount.
75
- - Prioritize lines with "TOTAL", "Amount Due", "Purchase", "Grand Total".
76
- - Include the **currency symbol/code** if present (e.g., `R238.00`, `$12.50`).
77
- - If no currency is visible, return just the number.
78
-
79
- 4. **Category**:
80
- - Based on the venue, infer the main category: groceries, restaurant, fuel, retail, pharmacy, etc.
81
- - If the venue is unclear, leave category as `null`.
82
-
83
- 5. **Output format**:
84
- Return strictly valid JSON with these keys:
85
- {{
86
- "venue": "...",
87
- "date": "...",
88
- "total": "...",
89
- "category": "..."
90
- }}
91
- - Do not add extra text or explanation outside the JSON.
92
-
93
- ---
94
-
95
- Receipt OCR text:
96
- {ocr_text}
97
- """)
98
 
99
 
100
  def run_langchain_with_text(receipt_text: str, image_path: str):
@@ -202,15 +188,7 @@ async def process_receipt_vision(file: UploadFile = File(...)):
202
 
203
  data_url = encode_image_to_data_url(cropped, format="JPEG")
204
 
205
- vision_instructions = (
206
- "You are an expert at reading receipts from an image. "
207
- "Extract these fields as strict JSON: {\\n"
208
- " \"venue\": string or null,\\n"
209
- " \"date\": string or null,\\n"
210
- " \"total\": string or number, include currency if shown,\\n"
211
- " \"category\": string or null\\n"
212
- "}. Do not include any extra commentary."
213
- )
214
 
215
  message = HumanMessage(
216
  content=[
@@ -223,9 +201,14 @@ async def process_receipt_vision(file: UploadFile = File(...)):
223
 
224
  return {
225
  "status": "success",
226
- "cropped_file": save_path,
227
- "bbox": bbox,
228
- "extracted": getattr(result, "content", str(result)),
 
 
 
 
 
229
  }
230
 
231
  if __name__ == "__main__":
 
52
  )
53
 
54
  # Define the prompt for categorization
55
+ UNIFIED_PROMPT_RULES = """
56
+ You are an expert at analyzing receipt content to extract structured fields.
 
57
 
58
  Rules:
59
+ 1. Venue:
60
+ - The store/restaurant/retailer name (often at the top). If brand + branch appear, include both.
61
+ - Ignore banks, payment processors, and card brands unless they are the only candidate.
62
+ - If uncertain, return null.
63
+
64
+ 2. Date:
65
+ - Accept formats like DD-MM-YY, YYYY-MM-DD, DD/MM/YYYY, optionally with time.
66
+ - If only a time is present (no date), return null.
67
+
68
+ 3. Total:
69
+ - The final purchase amount; prioritize lines with TOTAL/Amount Due/Purchase/Grand Total.
70
+ - Include currency symbol/code if shown (e.g., R238.00, $12.50). If not visible, return just the number.
71
+
72
+ 4. Category:
73
+ - Infer from venue/items if possible (groceries, restaurant, fuel, retail, pharmacy, etc.).
74
+ - If unclear, return null.
75
+
76
+ 5. Output format:
77
+ - Return strictly valid JSON with keys: {"venue", "date", "total", "category"} and no extra commentary.
78
+ """
79
+
80
+ text_prompt = ChatPromptTemplate.from_template(
81
+ UNIFIED_PROMPT_RULES
82
+ + "\n---\n\nReceipt OCR text:\n{ocr_text}\n"
83
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
 
86
  def run_langchain_with_text(receipt_text: str, image_path: str):
 
188
 
189
  data_url = encode_image_to_data_url(cropped, format="JPEG")
190
 
191
+ vision_instructions = UNIFIED_PROMPT_RULES
 
 
 
 
 
 
 
 
192
 
193
  message = HumanMessage(
194
  content=[
 
201
 
202
  return {
203
  "status": "success",
204
+ "receipts": [
205
+ {
206
+ "cropped_file": save_path,
207
+ "bbox": bbox,
208
+ "ocr_text": None,
209
+ "extracted": getattr(result, "content", str(result)),
210
+ }
211
+ ],
212
  }
213
 
214
  if __name__ == "__main__":