Seth0330 commited on
Commit
4ea086a
·
verified ·
1 Parent(s): 21e2212

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -70
app.py CHANGED
@@ -18,14 +18,36 @@ GEMMA_MODEL = "google/gemma-3-4b-it:free"
18
  st.set_page_config(page_title="EZOFIS Document Validation Agent", layout="wide")
19
  st.markdown("""
20
  <style>
21
- .step-num {background: #A020F0; color: #fff; border-radius: 999px;
22
- padding: 6px 13px; font-weight: 700; margin-right: 14px; font-size: 20px;
 
23
  display: inline-block; vertical-align: middle;}
24
  .stButton>button {
25
  background: #A020F0 !important; color: white !important; border-radius: 12px !important;
26
  padding: 10px 32px !important; font-weight: 700; border: none !important; font-size: 18px !important;
27
  margin-top: 12px !important;
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </style>
30
  """, unsafe_allow_html=True)
31
 
@@ -33,16 +55,51 @@ st.markdown(
33
  "<h1 style='font-weight:800; margin-bottom:8px;'>EZOFIS Document Validation Agent</h1>",
34
  unsafe_allow_html=True
35
  )
36
- st.markdown(
37
- "<div style='font-size:20px; margin-bottom:28px; color:#24345C;'>AI-driven, agentic document acceptance for mortgage and finance workflows.</div>",
38
- unsafe_allow_html=True
39
- )
40
-
41
- # ========== UI ==========
42
 
43
- # --- Step 0: Agent Instructions ---
44
- st.markdown("<span class='step-num'>0</span> <b>Instruct Agent</b>", unsafe_allow_html=True)
45
- sample_instruction = """You are a careful, expert document validation agent for mortgage and finance workflows.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  Before you answer, do this: Carefully scan the document for ANY evidence of regional/provincial or country-specific card types (such as "Ontario Health Card", "Medicare Card", "Insurance Card", "SIN", "Driver's License", "Passport", etc.)—be as specific as possible using visible card titles, authority names, or issuer logos.
48
 
@@ -50,63 +107,29 @@ Checklist for precision:
50
  - Prefer the **most specific** document type (e.g. "Ontario Health Card" over just "Identification Card" or "Provincial ID").
51
  - If there is any ambiguity, include relevant keywords from the card (like "Health", "Medicare", "OHIP", "SIN", "Social Insurance", "Driver", etc.) in the output type.
52
  - If still not sure, show your best guess but include all possible hints from the document text."""
53
- agent_instruction = st.text_area(
54
- "Instructions for the Document Validation Agent (edit as needed):",
55
- value=sample_instruction,
56
- height=240,
57
- key="agent_instruction"
58
- )
59
-
60
- # --- Step 0b: Current Date for Expiry ---
61
- st.markdown("<span class='step-num'>0b</span> <b>Set Current Date for Expiry Validation</b>", unsafe_allow_html=True)
62
- current_date = st.date_input(
63
- "Current date to be used by the agent for expiry checking",
64
- value=datetime.now().date(),
65
- key="current_date"
66
- )
67
- date_str = str(current_date)
68
-
69
- # --- Step 1: Checklist JSON input ---
70
- sample_checklist = '''{
71
- "required_documents": [
72
- {"type": "Driver's License", "description": "Government-issued photo ID"},
73
- {"type": "Passport", "description": "Valid passport"},
74
- {"type": "SIN Card", "description": "Social Insurance Number document"},
75
- {"type": "Bank Statement", "description": "Last 3 months bank statement"},
76
- {"type": "Employment Letter", "description": "Signed letter from employer"},
77
- {"type": "Pay Stub", "description": "Most recent pay stub"},
78
- {"type": "Proof of Address", "description": "Utility bill or lease"},
79
- {"type": "Ontario Health Card", "description": "Provincial health insurance card"}
80
- ]
81
- }'''
82
-
83
- st.markdown("<span class='step-num'>1</span> <b>Paste Mortgage Checklist (JSON)</b>", unsafe_allow_html=True)
84
- checklist_text = st.text_area(
85
- "Paste or edit your mortgage checklist JSON below:",
86
- value=sample_checklist,
87
- height=200,
88
- key="doc_checklist_json"
89
- )
90
- try:
91
- checklist = json.loads(checklist_text)
92
- required_types = [doc["type"] for doc in checklist["required_documents"]]
93
- except Exception as e:
94
- st.error("Invalid checklist JSON.")
95
- st.stop()
96
-
97
- # --- Step 2: Document upload ---
98
- st.markdown("<span class='step-num'>2</span> <b>Upload Document(s) to Validate</b>", unsafe_allow_html=True)
99
- uploaded_files = st.file_uploader(
100
- "Upload PDF, DOCX, XLSX, PNG, JPG, TIFF, etc.",
101
- type=["pdf", "docx", "xlsx", "xls", "png", "jpg", "jpeg", "tiff"],
102
- key="mortgage_files",
103
- accept_multiple_files=True
104
- )
105
-
106
- # --- Step 3: Thresholds ---
107
- st.markdown("<span class='step-num'>3</span> <b>Configure Acceptance Thresholds</b>", unsafe_allow_html=True)
108
- min_match_score = st.slider("Minimum Type Match Score (0-100)", 50, 100, 70, 1)
109
- min_confidence = st.slider("Minimum LLM Confidence (0-100)", 50, 100, 70, 1)
110
 
111
  # ========== FUNCTIONS ==========
112
 
@@ -280,8 +303,19 @@ def fuzzy_match_type(detected_type, checklist_types):
280
  best_score = score
281
  return best_type, best_score
282
 
 
 
 
 
 
 
 
 
283
  # ========== PROCESSING ==========
284
- if st.button("Run Document Validation", type="primary") and uploaded_files:
 
 
 
285
  results = []
286
  debug_data = []
287
 
@@ -375,9 +409,23 @@ if st.button("Run Document Validation", type="primary") and uploaded_files:
375
  debug_data.append({uploaded_file.name: debug})
376
  status_box.success("Validation complete. See result below.")
377
 
 
378
  if results:
379
  st.success("All validations complete.")
380
- st.dataframe(pd.DataFrame(results), use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  else:
382
  st.warning("No valid results.")
383
 
 
18
  st.set_page_config(page_title="EZOFIS Document Validation Agent", layout="wide")
19
  st.markdown("""
20
  <style>
21
+ .step-num {
22
+ background: #A020F0; color: #fff; border-radius: 999px;
23
+ padding: 6px 16px; font-weight: 700; margin-right: 14px; font-size: 18px;
24
  display: inline-block; vertical-align: middle;}
25
  .stButton>button {
26
  background: #A020F0 !important; color: white !important; border-radius: 12px !important;
27
  padding: 10px 32px !important; font-weight: 700; border: none !important; font-size: 18px !important;
28
  margin-top: 12px !important;
29
  }
30
+ /* Style result table headers */
31
+ .styled-table th {
32
+ background: #f3ecff !important;
33
+ color: #42318d !important;
34
+ font-weight: bold !important;
35
+ font-size: 16px !important;
36
+ padding: 10px 6px !important;
37
+ border-bottom: 2px solid #A020F0 !important;
38
+ }
39
+ .styled-table td {
40
+ font-size: 15px !important;
41
+ padding: 8px 4px !important;
42
+ word-break: break-word;
43
+ max-width: 220px;
44
+ }
45
+ .accepted-row {
46
+ background: #e7ffe7 !important;
47
+ }
48
+ .rejected-row {
49
+ background: #fff1f0 !important;
50
+ }
51
  </style>
52
  """, unsafe_allow_html=True)
53
 
 
55
  "<h1 style='font-weight:800; margin-bottom:8px;'>EZOFIS Document Validation Agent</h1>",
56
  unsafe_allow_html=True
57
  )
 
 
 
 
 
 
58
 
59
+ # ====== SIDE-BY-SIDE LAYOUT ======
60
+ col_left, col_right = st.columns([1.35, 1.05])
61
+
62
+ with col_left:
63
+ # Step 1: Checklist
64
+ st.markdown("<span class='step-num'>1</span> <b>Paste Mortgage Checklist (JSON)</b>", unsafe_allow_html=True)
65
+ sample_checklist = '''{
66
+ "required_documents": [
67
+ {"type": "Driver's License", "description": "Government-issued photo ID"},
68
+ {"type": "Passport", "description": "Valid passport"},
69
+ {"type": "SIN Card", "description": "Social Insurance Number document"},
70
+ {"type": "Bank Statement", "description": "Last 3 months bank statement"},
71
+ {"type": "Employment Letter", "description": "Signed letter from employer"},
72
+ {"type": "Pay Stub", "description": "Most recent pay stub"},
73
+ {"type": "Proof of Address", "description": "Utility bill or lease"},
74
+ {"type": "Ontario Health Card", "description": "Provincial health insurance card"}
75
+ ]
76
+ }'''
77
+ checklist_text = st.text_area(
78
+ "Paste or edit your mortgage checklist JSON below:",
79
+ value=sample_checklist,
80
+ height=220,
81
+ key="doc_checklist_json"
82
+ )
83
+ try:
84
+ checklist = json.loads(checklist_text)
85
+ required_types = [doc["type"] for doc in checklist["required_documents"]]
86
+ except Exception as e:
87
+ st.error("Invalid checklist JSON.")
88
+ st.stop()
89
+
90
+ # Step 2: Document upload
91
+ st.markdown("<span class='step-num'>2</span> <b>Upload Document(s) to Validate</b>", unsafe_allow_html=True)
92
+ uploaded_files = st.file_uploader(
93
+ "Upload PDF, DOCX, XLSX, PNG, JPG, TIFF, etc.",
94
+ type=["pdf", "docx", "xlsx", "xls", "png", "jpg", "jpeg", "tiff"],
95
+ key="mortgage_files",
96
+ accept_multiple_files=True
97
+ )
98
+
99
+ with col_right:
100
+ # Step 3: Agent instructions
101
+ st.markdown("<span class='step-num'>3</span> <b>Instruct Agent</b>", unsafe_allow_html=True)
102
+ sample_instruction = """You are a careful, expert document validation agent for mortgage and finance workflows.
103
 
104
  Before you answer, do this: Carefully scan the document for ANY evidence of regional/provincial or country-specific card types (such as "Ontario Health Card", "Medicare Card", "Insurance Card", "SIN", "Driver's License", "Passport", etc.)—be as specific as possible using visible card titles, authority names, or issuer logos.
105
 
 
107
  - Prefer the **most specific** document type (e.g. "Ontario Health Card" over just "Identification Card" or "Provincial ID").
108
  - If there is any ambiguity, include relevant keywords from the card (like "Health", "Medicare", "OHIP", "SIN", "Social Insurance", "Driver", etc.) in the output type.
109
  - If still not sure, show your best guess but include all possible hints from the document text."""
110
+ agent_instruction = st.text_area(
111
+ "Instructions for the Document Validation Agent (edit as needed):",
112
+ value=sample_instruction,
113
+ height=240,
114
+ key="agent_instruction"
115
+ )
116
+
117
+ # Step 4: Current date
118
+ st.markdown("<span class='step-num'>4</span> <b>Set Current Date for Expiry Validation</b>", unsafe_allow_html=True)
119
+ current_date = st.date_input(
120
+ "Current date to be used by the agent for expiry checking",
121
+ value=datetime.now().date(),
122
+ key="current_date"
123
+ )
124
+ date_str = str(current_date)
125
+
126
+ # Step 5: Thresholds
127
+ st.markdown("<span class='step-num'>5</span> <b>Configure Acceptance Thresholds</b>", unsafe_allow_html=True)
128
+ min_match_score = st.slider("Minimum Type Match Score (0-100)", 50, 100, 70, 1)
129
+ min_confidence = st.slider("Minimum LLM Confidence (0-100)", 50, 100, 70, 1)
130
+
131
+ # Step 6: Run button
132
+ run_btn = st.button("Run Document Validation", type="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  # ========== FUNCTIONS ==========
135
 
 
303
  best_score = score
304
  return best_type, best_score
305
 
306
+ def color_row(row):
307
+ if row["Accepted"] == "Yes":
308
+ return ['background-color: #e7ffe7'] * len(row)
309
+ elif row["Accepted"] == "No":
310
+ return ['background-color: #fff1f0'] * len(row)
311
+ else:
312
+ return [''] * len(row)
313
+
314
  # ========== PROCESSING ==========
315
+ if 'run_btn' not in locals():
316
+ run_btn = False
317
+
318
+ if run_btn and uploaded_files:
319
  results = []
320
  debug_data = []
321
 
 
409
  debug_data.append({uploaded_file.name: debug})
410
  status_box.success("Validation complete. See result below.")
411
 
412
+ # ==== Results table with custom styling ====
413
  if results:
414
  st.success("All validations complete.")
415
+ df = pd.DataFrame(results)
416
+ # Convert to HTML with classes for styling
417
+ def style_row(row):
418
+ color = "#e7ffe7" if row["Accepted"] == "Yes" else "#fff1f0"
419
+ return [f"background-color: {color}"]*len(row)
420
+ styled_df = df.style.apply(style_row, axis=1)\
421
+ .set_table_attributes('class="styled-table"')\
422
+ .set_properties(**{
423
+ 'font-size': '15px',
424
+ 'word-break': 'break-word',
425
+ 'border': '1px solid #ddd'
426
+ })
427
+ st.markdown('<h4 style="margin-top:28px;">Validation Results</h4>', unsafe_allow_html=True)
428
+ st.write(styled_df.to_html(escape=False), unsafe_allow_html=True)
429
  else:
430
  st.warning("No valid results.")
431