ngupta2026 commited on
Commit
cc8dce8
ยท
verified ยท
1 Parent(s): 44f3c50

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -54
app.py CHANGED
@@ -5,6 +5,8 @@ import torch
5
  import re
6
  import requests
7
  import os
 
 
8
 
9
  from transformers import LayoutLMTokenizerFast, LayoutLMForTokenClassification
10
 
@@ -13,21 +15,12 @@ from transformers import LayoutLMTokenizerFast, LayoutLMForTokenClassification
13
  # =====================================================
14
  RESEND_API_KEY = os.getenv("RESEND_API_KEY")
15
 
16
- # ๐Ÿ”ฅ IMPORTANT:
17
- # Use YOUR VERIFIED DOMAIN EMAIL
18
- # Example:
19
- # claims@send.yudham.com
20
  FROM_EMAIL = "AI Claims <claims@yudham.com>"
21
 
22
  MODEL_NAME = "ngupta2026/sroie-layoutlm"
23
 
24
- label2id = {
25
- "O": 0,
26
- "COMPANY": 1,
27
- "DATE": 2,
28
- "TOTAL": 3
29
- }
30
-
31
  id2label = {v: k for k, v in label2id.items()}
32
 
33
  # =====================================================
@@ -42,7 +35,7 @@ model.to(device)
42
  model.eval()
43
 
44
  # =====================================================
45
- # NORMALIZE BOX
46
  # =====================================================
47
  def normalize(box, width, height):
48
  return [
@@ -53,7 +46,7 @@ def normalize(box, width, height):
53
  ]
54
 
55
  # =====================================================
56
- # CONFIDENCE AVG
57
  # =====================================================
58
  def avg_conf(lst):
59
  if len(lst) == 0:
@@ -151,27 +144,15 @@ def extract_receipt(image):
151
  except:
152
  pass
153
 
154
- # FINAL CLEAN
155
- result["company"] = (
156
- " ".join(result["company"])
157
- if result["company"] else "Not Found"
158
- )
159
-
160
- result["date"] = (
161
- result["date"][0]
162
- if result["date"] else "Not Found"
163
- )
164
-
165
- result["total"] = (
166
- result["total"][-1]
167
- if result["total"] else "Not Found"
168
- )
169
-
170
- company_conf = avg_conf(conf_store["company"])
171
- date_conf = avg_conf(conf_store["date"])
172
- total_conf = avg_conf(conf_store["total"])
173
 
174
- overall = (company_conf + date_conf + total_conf) / 3
 
 
 
 
175
 
176
  result["confidence"] = round(overall, 3)
177
 
@@ -181,7 +162,7 @@ def extract_receipt(image):
181
  return {"error": str(e)}
182
 
183
  # =====================================================
184
- # DECISION ENGINE
185
  # =====================================================
186
  def decision_layer(conf):
187
 
@@ -195,12 +176,33 @@ def decision_layer(conf):
195
  return "REJECT"
196
 
197
  # =====================================================
198
- # EMAIL SEND
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  # =====================================================
200
- def send_claim_email(to_email, extracted):
201
 
202
  if not RESEND_API_KEY:
203
- return "โŒ Missing RESEND_API_KEY secret"
 
 
204
 
205
  subject = "Insurance Claim Request"
206
 
@@ -209,15 +211,30 @@ def send_claim_email(to_email, extracted):
209
 
210
  <p>Dear Claims Team,</p>
211
 
212
- <p>Please process reimbursement request.</p>
213
 
214
- <p><b>Provider Name:</b> {extracted['company']}</p>
215
  <p><b>Bill Date:</b> {extracted['date']}</p>
216
  <p><b>Claim Amount:</b> โ‚น{extracted['total']}</p>
217
 
 
 
218
  <p>Regards,<br>AI Claims System</p>
219
  """
220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  try:
222
  response = requests.post(
223
  "https://api.resend.com/emails",
@@ -225,17 +242,12 @@ def send_claim_email(to_email, extracted):
225
  "Authorization": f"Bearer {RESEND_API_KEY}",
226
  "Content-Type": "application/json"
227
  },
228
- json={
229
- "from": FROM_EMAIL,
230
- "to": [to_email],
231
- "subject": subject,
232
- "html": html_body
233
- },
234
- timeout=20
235
  )
236
 
237
  if response.status_code in [200, 201]:
238
- return f"โœ… Email sent successfully to {to_email}"
239
 
240
  else:
241
  return f"โŒ Email failed: {response.text}"
@@ -259,15 +271,15 @@ def process_and_send(image, email_id):
259
  extracted["decision"] = decision
260
 
261
  if decision == "AUTO_SEND":
262
- email_status = send_claim_email(email_id, extracted)
263
 
264
  elif decision == "REVIEW":
265
- email_status = f"โš ๏ธ Human review required (confidence={conf})"
266
 
267
  else:
268
- email_status = f"โŒ Rejected (low confidence={conf})"
269
 
270
- return extracted, email_status
271
 
272
  # =====================================================
273
  # UI
@@ -281,12 +293,12 @@ demo = gr.Interface(
281
  ],
282
 
283
  outputs=[
284
- gr.JSON(label="AI Extraction"),
285
  gr.Textbox(label="Email Status")
286
  ],
287
 
288
- title="๐Ÿ“„ AI Insurance Claim Generator",
289
- description="Upload receipt โ†’ Extract fields โ†’ Confidence Check โ†’ Auto Email"
290
  )
291
 
292
  demo.launch()
 
5
  import re
6
  import requests
7
  import os
8
+ import base64
9
+ import tempfile
10
 
11
  from transformers import LayoutLMTokenizerFast, LayoutLMForTokenClassification
12
 
 
15
  # =====================================================
16
  RESEND_API_KEY = os.getenv("RESEND_API_KEY")
17
 
18
+ # Use your VERIFIED sender email
 
 
 
19
  FROM_EMAIL = "AI Claims <claims@yudham.com>"
20
 
21
  MODEL_NAME = "ngupta2026/sroie-layoutlm"
22
 
23
+ label2id = {"O": 0, "COMPANY": 1, "DATE": 2, "TOTAL": 3}
 
 
 
 
 
 
24
  id2label = {v: k for k, v in label2id.items()}
25
 
26
  # =====================================================
 
35
  model.eval()
36
 
37
  # =====================================================
38
+ # NORMALIZE BOXES
39
  # =====================================================
40
  def normalize(box, width, height):
41
  return [
 
46
  ]
47
 
48
  # =====================================================
49
+ # CONFIDENCE HELPER
50
  # =====================================================
51
  def avg_conf(lst):
52
  if len(lst) == 0:
 
144
  except:
145
  pass
146
 
147
+ result["company"] = " ".join(result["company"]) if result["company"] else "Not Found"
148
+ result["date"] = result["date"][0] if result["date"] else "Not Found"
149
+ result["total"] = result["total"][-1] if result["total"] else "Not Found"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
+ overall = (
152
+ avg_conf(conf_store["company"]) +
153
+ avg_conf(conf_store["date"]) +
154
+ avg_conf(conf_store["total"])
155
+ ) / 3
156
 
157
  result["confidence"] = round(overall, 3)
158
 
 
162
  return {"error": str(e)}
163
 
164
  # =====================================================
165
+ # DECISION LAYER
166
  # =====================================================
167
  def decision_layer(conf):
168
 
 
176
  return "REJECT"
177
 
178
  # =====================================================
179
+ # IMAGE TO PDF BASE64
180
+ # =====================================================
181
+ def create_pdf_base64(image):
182
+
183
+ with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f:
184
+
185
+ pdf_path = f.name
186
+
187
+ image = image.convert("RGB")
188
+ image.save(pdf_path, "PDF")
189
+
190
+ with open(pdf_path, "rb") as file:
191
+ pdf_bytes = file.read()
192
+
193
+ encoded = base64.b64encode(pdf_bytes).decode("utf-8")
194
+
195
+ return encoded
196
+
197
+ # =====================================================
198
+ # SEND EMAIL WITH PDF ATTACHMENT
199
  # =====================================================
200
+ def send_claim_email(to_email, extracted, image):
201
 
202
  if not RESEND_API_KEY:
203
+ return "โŒ Missing RESEND_API_KEY"
204
+
205
+ pdf_base64 = create_pdf_base64(image)
206
 
207
  subject = "Insurance Claim Request"
208
 
 
211
 
212
  <p>Dear Claims Team,</p>
213
 
214
+ <p>Please process claim reimbursement request.</p>
215
 
216
+ <p><b>Provider:</b> {extracted['company']}</p>
217
  <p><b>Bill Date:</b> {extracted['date']}</p>
218
  <p><b>Claim Amount:</b> โ‚น{extracted['total']}</p>
219
 
220
+ <p>Attached: Receipt PDF</p>
221
+
222
  <p>Regards,<br>AI Claims System</p>
223
  """
224
 
225
+ payload = {
226
+ "from": FROM_EMAIL,
227
+ "to": [to_email],
228
+ "subject": subject,
229
+ "html": html_body,
230
+ "attachments": [
231
+ {
232
+ "filename": "receipt.pdf",
233
+ "content": pdf_base64
234
+ }
235
+ ]
236
+ }
237
+
238
  try:
239
  response = requests.post(
240
  "https://api.resend.com/emails",
 
242
  "Authorization": f"Bearer {RESEND_API_KEY}",
243
  "Content-Type": "application/json"
244
  },
245
+ json=payload,
246
+ timeout=30
 
 
 
 
 
247
  )
248
 
249
  if response.status_code in [200, 201]:
250
+ return f"โœ… Email + PDF sent to {to_email}"
251
 
252
  else:
253
  return f"โŒ Email failed: {response.text}"
 
271
  extracted["decision"] = decision
272
 
273
  if decision == "AUTO_SEND":
274
+ status = send_claim_email(email_id, extracted, image)
275
 
276
  elif decision == "REVIEW":
277
+ status = f"โš ๏ธ Human review needed (confidence={conf})"
278
 
279
  else:
280
+ status = f"โŒ Rejected (confidence={conf})"
281
 
282
+ return extracted, status
283
 
284
  # =====================================================
285
  # UI
 
293
  ],
294
 
295
  outputs=[
296
+ gr.JSON(label="Extracted Fields"),
297
  gr.Textbox(label="Email Status")
298
  ],
299
 
300
+ title="๐Ÿ“„ AI Insurance Claim Generator + PDF",
301
+ description="Upload receipt โ†’ Extract data โ†’ Auto email with PDF attachment"
302
  )
303
 
304
  demo.launch()