Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import os
|
3 |
+
from typing import List, Dict
|
4 |
+
import json
|
5 |
+
|
6 |
+
# Mock backend functions to simulate AWS Bedrock Agents
|
7 |
+
def validate_documents(files: List[str]) -> str:
|
8 |
+
"""Simulate Intake Agent: Check if all required docs are present."""
|
9 |
+
required = ["ID", "Pay Stubs", "W-2", "Tax Returns", "Bank Statements", "Offer", "Insurance", "Title"]
|
10 |
+
uploaded = [os.path.basename(f).split(".")[0] for f in files]
|
11 |
+
missing = [doc for doc in required if doc not in uploaded]
|
12 |
+
if missing:
|
13 |
+
return f"Missing documents: {', '.join(missing)}"
|
14 |
+
return "All documents validated successfully."
|
15 |
+
|
16 |
+
def extract_data(files: List[str], ssn: str) -> Dict:
|
17 |
+
"""Simulate Extraction Agent: Extract data from documents."""
|
18 |
+
return {
|
19 |
+
"application_id": 123,
|
20 |
+
"ssn": ssn,
|
21 |
+
"monthly_income": 5000,
|
22 |
+
"monthly_debts": 1000,
|
23 |
+
"credit_score": 650,
|
24 |
+
"property_value": 300000,
|
25 |
+
"loan_amount": 240000,
|
26 |
+
"insurance_coverage": "12_months",
|
27 |
+
"title_status": "Clear"
|
28 |
+
}
|
29 |
+
|
30 |
+
def analyze_data(data: Dict) -> Dict:
|
31 |
+
"""Simulate Credit/Capacity/Collateral/Compliance Agents: Analyze data."""
|
32 |
+
dti = (data["monthly_debts"] / data["monthly_income"]) * 100
|
33 |
+
ltv = (data["loan_amount"] / data["property_value"]) * 100
|
34 |
+
flags = []
|
35 |
+
if dti > 45:
|
36 |
+
flags.append("High DTI")
|
37 |
+
if data["credit_score"] < 620:
|
38 |
+
flags.append("Low credit score")
|
39 |
+
if "Clear" not in data["title_status"]:
|
40 |
+
flags.append("Title issue")
|
41 |
+
return {
|
42 |
+
"DTI": round(dti, 2),
|
43 |
+
"LTV": round(ltv, 2),
|
44 |
+
"credit_score": data["credit_score"],
|
45 |
+
"flags": flags,
|
46 |
+
"status": "Needs review" if flags else "Ready for approval"
|
47 |
+
}
|
48 |
+
|
49 |
+
def handle_conditions(additional_files: List[str], comments: str) -> str:
|
50 |
+
"""Simulate Conditions Agent: Process additional uploads."""
|
51 |
+
if additional_files:
|
52 |
+
return f"Additional files received: {', '.join([os.path.basename(f) for f in additional_files])}. Comments: {comments}"
|
53 |
+
return "No additional files uploaded."
|
54 |
+
|
55 |
+
def finalize_approval(approve: bool, comments: str, analysis: Dict) -> str:
|
56 |
+
"""Simulate Final Approval Agent: Finalize decision."""
|
57 |
+
if approve and not analysis["flags"]:
|
58 |
+
return "Clear to Close. Closing package generated."
|
59 |
+
elif approve:
|
60 |
+
return f"Approved with conditions: {', '.join(analysis['flags'])}. Comments: {comments}"
|
61 |
+
else:
|
62 |
+
return f"Rejected. Comments: {comments}"
|
63 |
+
|
64 |
+
# Gradio Interface
|
65 |
+
with gr.Blocks(title="Mortgage Underwriting Automation") as app:
|
66 |
+
gr.Markdown("# Mortgage Underwriting Automation")
|
67 |
+
|
68 |
+
# Section 1: Document Upload
|
69 |
+
with gr.Row():
|
70 |
+
with gr.Column():
|
71 |
+
gr.Markdown("## Upload Documents")
|
72 |
+
files_input = gr.File(label="Upload Documents (ID, Pay Stubs, W-2s, etc.)", file_count="multiple", file_types=[".pdf", ".png", ".jpg"])
|
73 |
+
ssn_input = gr.Textbox(label="Social Security Number", placeholder="XXX-XX-XXXX")
|
74 |
+
validate_btn = gr.Button("Validate Documents")
|
75 |
+
validate_output = gr.Textbox(label="Validation Result")
|
76 |
+
validate_btn.click(fn=validate_documents, inputs=files_input, outputs=validate_output)
|
77 |
+
|
78 |
+
# Section 2: Data Extraction and Analysis
|
79 |
+
with gr.Row():
|
80 |
+
with gr.Column():
|
81 |
+
gr.Markdown("## Extracted Data and Analysis")
|
82 |
+
extract_btn = gr.Button("Extract and Analyze")
|
83 |
+
analysis_output = gr.JSON(label="Analysis Results (DTI, LTV, Flags)")
|
84 |
+
extract_btn.click(fn=lambda files, ssn: analyze_data(extract_data(files, ssn)), inputs=[files_input, ssn_input], outputs=analysis_output)
|
85 |
+
|
86 |
+
# Section 3: Conditions
|
87 |
+
with gr.Row():
|
88 |
+
with gr.Column():
|
89 |
+
gr.Markdown("## Conditions (Additional Documents)")
|
90 |
+
additional_files = gr.File(label="Upload Additional Documents (e.g., Gift Letter)", file_count="multiple", file_types=[".pdf", ".png", ".jpg"])
|
91 |
+
condition_comments = gr.Textbox(label="Comments for Conditions")
|
92 |
+
condition_btn = gr.Button("Submit Additional Documents")
|
93 |
+
condition_output = gr.Textbox(label="Condition Status")
|
94 |
+
condition_btn.click(fn=handle_conditions, inputs=[additional_files, condition_comments], outputs=condition_output)
|
95 |
+
|
96 |
+
# Section 4: Final Approval
|
97 |
+
with gr.Row():
|
98 |
+
with gr.Column():
|
99 |
+
gr.Markdown("## Final Approval")
|
100 |
+
approve_radio = gr.Radio(choices=["Approve", "Reject"], label="Decision")
|
101 |
+
approval_comments = gr.Textbox(label="Approval/Rejection Comments")
|
102 |
+
approve_btn = gr.Button("Submit Decision")
|
103 |
+
final_output = gr.Textbox(label="Final Status")
|
104 |
+
approve_btn.click(fn=finalize_approval, inputs=[approve_radio, approval_comments, analysis_output], outputs=final_output)
|
105 |
+
|
106 |
+
app.launch()
|