Seth0330 commited on
Commit
91108ba
·
verified ·
1 Parent(s): f52c5eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -20
app.py CHANGED
@@ -48,12 +48,11 @@ st.markdown("""
48
  background: #F3F6FB !important;
49
  border-radius: 999px;
50
  }
51
- .css-12w0qpk {padding-top: 0rem;} /* Removes extra padding */
52
- .css-1kyxreq {padding-top: 0rem;} /* Removes extra padding */
53
  </style>
54
  """, unsafe_allow_html=True)
55
 
56
- # --- Model Definitions ---
57
  MODELS = {
58
  "OpenAI GPT-4.1": {
59
  "api_url": "https://api.openai.com/v1/chat/completions",
@@ -140,8 +139,72 @@ def get_extraction_prompt(model_choice, txt):
140
  "Shipment/invoice-level fields such as CAR NUMBER, SHIPPING POINT, SHIPMENT NUMBER, CURRENCY, etc., must go ONLY into the 'invoice_header', not as line item fields.\n"
141
  "Use this schema:\n"
142
  '{\n'
143
- ' "invoice_header": {...},\n'
144
- ' "line_items": [{...}]\n'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  '}'
146
  "\nIf a field is missing for a line item or header, use null. "
147
  "Do not invent fields. Do not add any header or shipment data to any line item. Return ONLY the JSON object, no explanation.\n"
@@ -150,9 +213,8 @@ def get_extraction_prompt(model_choice, txt):
150
  )
151
 
152
  def ensure_total_due(invoice_header):
153
- # Prefer total_before_tax if total_due mismatches in scoring
154
  if invoice_header.get("total_due") in [None, ""]:
155
- for field in ["total_before_tax", "invoice_total", "invoice_value", "balance_due", "amount_paid"]:
156
  if field in invoice_header and invoice_header[field]:
157
  invoice_header["total_due"] = invoice_header[field]
158
  break
@@ -210,9 +272,7 @@ def find_best_po_match(inv, po_df, weight_supplier, weight_po_number, weight_cur
210
  inv_supplier = inv_hdr.get("supplier_name") or ""
211
  inv_po_number = inv_hdr.get("purchase_order_number") or inv_hdr.get("po_number") or inv_hdr.get("order_number") or ""
212
  inv_currency = inv_hdr.get("currency") or ""
213
- # -- Try both total_due and total_before_tax for matching
214
  inv_total_due = clean_num(inv_hdr.get("total_due"))
215
- inv_total_before_tax = clean_num(inv_hdr.get("total_before_tax"))
216
  inv_line_items = inv.get("line_items", [])
217
 
218
  scores = []
@@ -252,15 +312,10 @@ def find_best_po_match(inv, po_df, weight_supplier, weight_po_number, weight_cur
252
  "score": s_currency
253
  })
254
 
255
- # Try total_due, fallback to total_before_tax
256
- s_total = 0
257
- if inv_total_due is not None and po_total is not None and abs(inv_total_due - po_total) < 2:
258
- s_total = 100
259
- elif inv_total_before_tax is not None and po_total is not None and abs(inv_total_before_tax - po_total) < 2:
260
- s_total = 100
261
  field_details.append({
262
- "field": "Total Due or Before Tax",
263
- "invoice": inv_total_due if s_total else inv_total_before_tax,
264
  "po": po_total,
265
  "score": s_total
266
  })
@@ -316,7 +371,7 @@ def find_best_po_match(inv, po_df, weight_supplier, weight_po_number, weight_cur
316
  f"Supplier match: {s_supplier}/100 (invoice: '{inv_supplier}' vs PO: '{po_supplier}'), "
317
  f"PO Number: {s_po_number}/100 ({'found anywhere in JSON' if s_po_number else 'not found'}), "
318
  f"Currency: {s_currency}/100 (invoice: '{inv_currency}' vs PO: '{po_currency}'), "
319
- f"Total: {'match' if s_total else 'no match'} (invoice: {inv_total_due if s_total else inv_total_before_tax} vs PO: {po_total}), "
320
  f"Line item best match: {int(line_item_score)}/100. {line_reason}"
321
  )
322
 
@@ -330,8 +385,7 @@ def find_best_po_match(inv, po_df, weight_supplier, weight_po_number, weight_cur
330
  "best_line_detail": best_line_detail,
331
  "total_score": total_score,
332
  "line_reason": line_reason,
333
- "inv_total_due": inv_total_due,
334
- "inv_total_before_tax": inv_total_before_tax
335
  }
336
  scores.append((row, total_score, reason, debug))
337
 
 
48
  background: #F3F6FB !important;
49
  border-radius: 999px;
50
  }
51
+ .css-12w0qpk {padding-top: 0rem;}
52
+ .css-1kyxreq {padding-top: 0rem;}
53
  </style>
54
  """, unsafe_allow_html=True)
55
 
 
56
  MODELS = {
57
  "OpenAI GPT-4.1": {
58
  "api_url": "https://api.openai.com/v1/chat/completions",
 
139
  "Shipment/invoice-level fields such as CAR NUMBER, SHIPPING POINT, SHIPMENT NUMBER, CURRENCY, etc., must go ONLY into the 'invoice_header', not as line item fields.\n"
140
  "Use this schema:\n"
141
  '{\n'
142
+ ' "invoice_header": {\n'
143
+ ' "car_number": "string or null",\n'
144
+ ' "shipment_number": "string or null",\n'
145
+ ' "shipping_point": "string or null",\n'
146
+ ' "currency": "string or null",\n'
147
+ ' "invoice_number": "string or null",\n'
148
+ ' "invoice_date": "string or null",\n'
149
+ ' "order_number": "string or null",\n'
150
+ ' "customer_order_number": "string or null",\n'
151
+ ' "our_order_number": "string or null",\n'
152
+ ' "sales_order_number": "string or null",\n'
153
+ ' "purchase_order_number": "string or null",\n'
154
+ ' "order_date": "string or null",\n'
155
+ ' "supplier_name": "string or null",\n'
156
+ ' "supplier_address": "string or null",\n'
157
+ ' "supplier_phone": "string or null",\n'
158
+ ' "supplier_email": "string or null",\n'
159
+ ' "supplier_tax_id": "string or null",\n'
160
+ ' "customer_name": "string or null",\n'
161
+ ' "customer_address": "string or null",\n'
162
+ ' "customer_phone": "string or null",\n'
163
+ ' "customer_email": "string or null",\n'
164
+ ' "customer_tax_id": "string or null",\n'
165
+ ' "ship_to_name": "string or null",\n'
166
+ ' "ship_to_address": "string or null",\n'
167
+ ' "bill_to_name": "string or null",\n'
168
+ ' "bill_to_address": "string or null",\n'
169
+ ' "remit_to_name": "string or null",\n'
170
+ ' "remit_to_address": "string or null",\n'
171
+ ' "tax_id": "string or null",\n'
172
+ ' "tax_registration_number": "string or null",\n'
173
+ ' "vat_number": "string or null",\n'
174
+ ' "payment_terms": "string or null",\n'
175
+ ' "payment_method": "string or null",\n'
176
+ ' "payment_reference": "string or null",\n'
177
+ ' "bank_account_number": "string or null",\n'
178
+ ' "iban": "string or null",\n'
179
+ ' "swift_code": "string or null",\n'
180
+ ' "total_before_tax": "string or null",\n'
181
+ ' "tax_amount": "string or null",\n'
182
+ ' "tax_rate": "string or null",\n'
183
+ ' "shipping_charges": "string or null",\n'
184
+ ' "discount": "string or null",\n'
185
+ ' "total_due": "string or null",\n'
186
+ ' "amount_paid": "string or null",\n'
187
+ ' "balance_due": "string or null",\n'
188
+ ' "due_date": "string or null",\n'
189
+ ' "invoice_status": "string or null",\n'
190
+ ' "reference_number": "string or null",\n'
191
+ ' "project_code": "string or null",\n'
192
+ ' "department": "string or null",\n'
193
+ ' "contact_person": "string or null",\n'
194
+ ' "notes": "string or null",\n'
195
+ ' "additional_info": "string or null"\n'
196
+ ' },\n'
197
+ ' "line_items": [\n'
198
+ ' {\n'
199
+ ' "quantity": "string or null",\n'
200
+ ' "units": "string or null",\n'
201
+ ' "description": "string or null",\n'
202
+ ' "footage": "string or null",\n'
203
+ ' "price": "string or null",\n'
204
+ ' "amount": "string or null",\n'
205
+ ' "notes": "string or null"\n'
206
+ ' }\n'
207
+ ' ]\n'
208
  '}'
209
  "\nIf a field is missing for a line item or header, use null. "
210
  "Do not invent fields. Do not add any header or shipment data to any line item. Return ONLY the JSON object, no explanation.\n"
 
213
  )
214
 
215
  def ensure_total_due(invoice_header):
 
216
  if invoice_header.get("total_due") in [None, ""]:
217
+ for field in ["invoice_total", "invoice_value", "total_before_tax", "balance_due", "amount_paid"]:
218
  if field in invoice_header and invoice_header[field]:
219
  invoice_header["total_due"] = invoice_header[field]
220
  break
 
272
  inv_supplier = inv_hdr.get("supplier_name") or ""
273
  inv_po_number = inv_hdr.get("purchase_order_number") or inv_hdr.get("po_number") or inv_hdr.get("order_number") or ""
274
  inv_currency = inv_hdr.get("currency") or ""
 
275
  inv_total_due = clean_num(inv_hdr.get("total_due"))
 
276
  inv_line_items = inv.get("line_items", [])
277
 
278
  scores = []
 
312
  "score": s_currency
313
  })
314
 
315
+ s_total = 100 if inv_total_due is not None and po_total is not None and abs(inv_total_due - po_total) < 2 else 0
 
 
 
 
 
316
  field_details.append({
317
+ "field": "Total Due",
318
+ "invoice": inv_total_due,
319
  "po": po_total,
320
  "score": s_total
321
  })
 
371
  f"Supplier match: {s_supplier}/100 (invoice: '{inv_supplier}' vs PO: '{po_supplier}'), "
372
  f"PO Number: {s_po_number}/100 ({'found anywhere in JSON' if s_po_number else 'not found'}), "
373
  f"Currency: {s_currency}/100 (invoice: '{inv_currency}' vs PO: '{po_currency}'), "
374
+ f"Total Due: {'match' if s_total else 'no match'} (invoice: {inv_total_due} vs PO: {po_total}), "
375
  f"Line item best match: {int(line_item_score)}/100. {line_reason}"
376
  )
377
 
 
385
  "best_line_detail": best_line_detail,
386
  "total_score": total_score,
387
  "line_reason": line_reason,
388
+ "inv_total_due": inv_total_due
 
389
  }
390
  scores.append((row, total_score, reason, debug))
391