ifiecas commited on
Commit
b6fcc7d
·
verified ·
1 Parent(s): 5fc3fc3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +466 -227
app.py CHANGED
@@ -3,19 +3,159 @@ import joblib
3
  import numpy as np
4
  from huggingface_hub import hf_hub_download
5
 
6
- # Page setup
7
  st.set_page_config(
8
  page_title="Loan Approval System",
9
  page_icon="🏦",
10
- layout="wide",
11
  initial_sidebar_state="collapsed"
12
  )
13
 
14
- # Custom styling (retain your existing full CSS here — unchanged)
15
- # You can paste your full <style> block here as-is
16
- st.markdown("""<style>...your existing CSS...</style>""", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # Load model once using caching
19
  @st.cache_resource
20
  def load_model():
21
  model_path = hf_hub_download(repo_id="ifiecas/LoanApproval-DT-v1.0", filename="best_pruned_dt.pkl")
@@ -23,279 +163,378 @@ def load_model():
23
 
24
  model = load_model()
25
 
 
 
 
26
 
27
- # Application banner
28
- st.markdown('<img src="https://i.postimg.cc/R0gGW9kb/ACTION-PLAN.png" class="banner-image" alt="SmartLoanAI Banner">', unsafe_allow_html=True)
29
-
30
- # Global disclaimer
31
- st.markdown("""<div class="footer-disclaimer" style="margin-bottom: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107;">
32
- <p><strong>Educational Project Disclaimer:</strong> This tool is a demonstration of machine learning model deployment and is not a real financial service. Loan decisions shown here are based on a sample dataset and trained model, intended for educational use only.</p>
33
- </div>""", unsafe_allow_html=True)
34
-
35
-
36
- # Use Streamlit Tabs
37
- tab_application, tab_about = st.tabs(["📝 Loan Application", "ℹ️ About the System"])
38
 
39
- with tab_application:
40
- # Header
41
- st.markdown("""
42
- <h2 style="text-align: center; color: var(--primary-purple-dark); margin-bottom: 20px;">
43
- Smart Loan Application System
44
- </h2>
45
- <p style="text-align: center; margin-bottom: 30px; font-size: 1.1rem;">
46
- Fill out the form below to check your loan eligibility. Our system will evaluate your information instantly.
47
- </p>
48
- """, unsafe_allow_html=True)
49
-
50
- # Input Sections
51
- st.markdown('<div class="section-card"><h3>👤 Personal Information</h3>', unsafe_allow_html=True)
52
- col1, col2, col3 = st.columns(3)
53
  with col1:
54
  gender = st.selectbox("Gender", ["Male", "Female"])
55
- number_of_dependents = st.number_input("Number of Dependents", min_value=0, max_value=10, value=0)
56
-
57
  with col2:
58
  marital_status = st.selectbox("Marital Status", ["Married", "Not Married"])
59
- self_employed = st.selectbox("Self-Employed", ["No", "Yes"])
60
-
61
- with col3:
62
- education = st.selectbox("Education Level", ["Graduate", "Under Graduate"])
63
  st.markdown('</div>', unsafe_allow_html=True)
64
-
65
- st.markdown('<div class="section-card"><h3>💰 Financial Details</h3>', unsafe_allow_html=True)
66
- col1, col2, col3 = st.columns(3)
 
 
67
  with col1:
68
  applicant_income = st.number_input("Monthly Income ($)", min_value=0, value=5000)
 
69
  credit_history = st.selectbox("Credit History Status", [1, 0],
70
- format_func=lambda x: "Good Credit History (1)" if x == 1 else "Poor Credit History (0)")
71
-
72
  with col2:
73
  coapplicant_income = st.number_input("Co-Applicant's Income ($)", min_value=0)
74
- location = st.selectbox("Property Location", ["Urban", "Semiurban", "Rural"])
75
-
76
- with col3:
77
- loan_amount = st.number_input("Loan Amount ($)", min_value=0, value=100000)
78
  loan_term = st.slider("Loan Term (months)", min_value=12, max_value=360, value=180, step=12)
 
 
79
  st.markdown('</div>', unsafe_allow_html=True)
80
-
81
- # Summary Section
 
 
82
  total_income = applicant_income + coapplicant_income
83
- interest_rate = 0.05
 
 
84
  monthly_interest = interest_rate / 12
85
  num_payments = loan_term
86
-
 
87
  if monthly_interest == 0 or num_payments == 0:
88
  monthly_payment = 0
89
  else:
90
  monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \
91
- ((1 + monthly_interest) ** num_payments - 1)
92
-
93
- debt_to_income_ratio = (monthly_payment / total_income) if total_income > 0 else 0
94
- debt_to_income_percent = debt_to_income_ratio * 100
95
-
96
- # Metrics
97
- st.markdown('<div class="section-card"><h3>📊 Application Summary</h3>', unsafe_allow_html=True)
98
- col1, col2, col3, col4 = st.columns(4)
99
- col1.metric("Total Monthly Income", f"${total_income:,.2f}")
100
- col2.metric("Estimated Monthly Payment", f"${monthly_payment:,.2f}")
101
- col3.metric("Loan Term", f"{loan_term // 12} years")
102
- col4.metric("Debt-to-Income Ratio", f"{debt_to_income_percent:.1f}%",
103
- delta=f"{debt_to_income_percent - 36:.1f}%" if debt_to_income_percent > 36 else "-",
104
- delta_color="normal" if debt_to_income_percent < 36 else "inverse")
105
-
106
- st.caption("Note: Estimated payment assumes a 5.0% annual interest rate. A healthy debt-to-income ratio is usually under 36%.")
 
 
 
107
  st.markdown('</div>', unsafe_allow_html=True)
108
-
109
-
110
- # Action Buttons
111
- col_main, col_reset = st.columns([3, 1])
112
- with col_main:
113
- check_button = st.button("🔍 Check Loan Approval Status", use_container_width=True)
114
- with col_reset:
115
- reset_button = st.button("🔄 Reset Form", use_container_width=True, help="Clear the form and start over")
116
-
117
- if reset_button:
 
 
 
118
  st.session_state.restart_clicked = True
119
- st.rerun()
120
-
121
- # Function to preprocess inputs
122
- def prepare_input():
123
  gender_num = 0 if gender == "Male" else 1
124
- marital_status_num = 1 if marital_status == "Married" else 0
125
- education_num = 1 if education == "Graduate" else 0
126
- self_employed_num = 1 if self_employed == "Yes" else 0
127
- credit_history_num = credit_history
 
 
128
  location_semiurban = 1 if location == "Semiurban" else 0
129
  location_urban = 1 if location == "Urban" else 0
 
 
130
  term_years = loan_term / 12
131
- credit_interaction = loan_amount * credit_history_num
132
- income_term_ratio = total_income / term_years if term_years > 0 else 0
133
-
 
 
 
 
134
  return np.array([[
135
  gender_num, marital_status_num, number_of_dependents, education_num, self_employed_num,
136
  applicant_income, coapplicant_income, loan_amount, credit_history_num,
137
- total_income, debt_to_income_ratio, location_semiurban, location_urban, term_years,
138
- credit_interaction, income_term_ratio
139
  ]])
140
-
141
- # Make prediction and display results
142
- if check_button:
143
- st.toast(" Prediction complete! Scroll down to view your result.")
144
- with st.spinner("Analyzing your application..."):
145
- features = prepare_input()
146
- model_result = model.predict(features)[0]
147
-
148
- # Manual override rules
149
- manually_rejected = False
150
- reason = ""
151
  if total_income < 1500:
152
- manually_rejected = True
153
- reason = "Total income is below the required minimum of $1,500."
154
- elif debt_to_income_percent > 50:
155
- manually_rejected = True
156
- reason = "Debt-to-income ratio is too high (above 50%)."
157
- elif credit_history == 0 and debt_to_income_percent > 35:
158
- manually_rejected = True
159
- reason = "Poor credit history and high debt-to-income ratio."
160
-
161
- approved = (model_result == 1) and not manually_rejected
162
-
163
- # Display outcome
164
- if approved:
165
  st.markdown("""
166
  <div class="result-approved">
167
  <h3 style="color: #2E7D32;">✅ Loan Approved</h3>
168
- <p>Congratulations! Based on your information, you meet the eligibility criteria.</p>
169
- <ol>
170
- <li>Verification of documents</li>
171
- <li>Loan term negotiation</li>
172
- <li>Disbursement of funds</li>
173
- </ol>
174
- <p><em>This result is part of an educational simulation, not a real financial offer.</em></p>
175
  </div>
176
  """, unsafe_allow_html=True)
177
  else:
178
- st.markdown(f"""
179
  <div class="result-rejected">
180
  <h3 style="color: #C62828;">❌ Loan Not Approved</h3>
181
- <p>Unfortunately, we cannot approve your application at this time.</p>
182
- <p><strong>Reason:</strong> {reason if reason else "Application does not meet current criteria."}</p>
183
- <p><strong>Suggestions:</strong></p>
184
- <ul>
185
- <li>Improve your credit history</li>
186
- <li>Lower your requested loan amount</li>
187
- <li>Add a co-applicant with income</li>
188
- <li>Reduce existing debt</li>
189
- </ul>
190
  </div>
191
  """, unsafe_allow_html=True)
192
 
193
-
194
- with tab_about:
195
- # Custom styling (already applied globally)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
- # Container start
198
  st.markdown('<div class="about-container">', unsafe_allow_html=True)
199
-
200
- # System Overview
201
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
202
  st.markdown('<h2 class="section-header">About the Loan Approval System</h2>', unsafe_allow_html=True)
203
- st.markdown("""
204
- <p class="about-text">
205
- This prototype demonstrates a machine learning model deployed as an interactive loan approval simulation.
206
- It evaluates user inputs — such as income, credit history, and loan amount — to assess eligibility.
207
- </p>
208
- """, unsafe_allow_html=True)
209
  st.markdown('</div>', unsafe_allow_html=True)
210
-
211
- # Model Info
212
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
213
- st.markdown('<h2 class="section-header">Machine Learning Model Details</h2>', unsafe_allow_html=True)
214
- st.markdown("""
215
- <p class="about-text">
216
- The system uses a Decision Tree classifier. After evaluating multiple models (Logistic Regression,
217
- Random Forest, Support Vector Machine), the Decision Tree performed best with the selected features.
218
- Cost Complexity Pruning was used to fine-tune and avoid overfitting.
219
- </p>
220
- """, unsafe_allow_html=True)
221
  st.markdown('</div>', unsafe_allow_html=True)
222
-
223
- # Performance Metrics
224
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
225
- st.markdown('<h2 class="section-header">Model Performance</h2>', unsafe_allow_html=True)
226
- st.markdown("""
227
- <div class="metrics-container">
228
- <div class="metric-card">
229
- <div class="metric-value">83.61%</div>
230
- <div class="metric-label">Accuracy</div>
231
- </div>
232
- <div class="metric-card">
233
- <div class="metric-value">80.77%</div>
234
- <div class="metric-label">Precision</div>
235
- </div>
236
- <div class="metric-card">
237
- <div class="metric-value">100.00%</div>
238
- <div class="metric-label">Recall</div>
239
- </div>
240
- <div class="metric-card">
241
- <div class="metric-value">89.36%</div>
242
- <div class="metric-label">F1 Score</div>
243
- </div>
244
- </div>
245
- """, unsafe_allow_html=True)
246
-
247
- # Resource Link
248
- st.markdown("""
249
- <p class="about-text">
250
- View the full modeling process, including feature engineering and model comparisons, at
251
- <a href="https://github.com/ifiecas/bankloan2" target="_blank" style="color: #2563eb;">this GitHub repository</a>.
252
- </p>
253
- """, unsafe_allow_html=True)
254
-
255
- # Video Embed
256
- st.markdown('<h2 class="section-header">Video Overview</h2>', unsafe_allow_html=True)
 
 
 
 
 
257
  st.markdown("""
258
- <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
259
- <iframe
260
- style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
261
- src="https://www.youtube.com/embed/y88GidhkAE8?si=iesfB084u4qrtPB_"
262
- title="Assessment Explanation"
263
- frameborder="0"
264
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
265
- allowfullscreen>
266
- </iframe>
267
- </div>
268
  """, unsafe_allow_html=True)
269
-
270
- # Author Credit
 
 
271
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
272
- st.markdown('<h2 class="section-header">About the Creator</h2>', unsafe_allow_html=True)
273
- st.markdown("""
274
- <div class="author-bio">
275
- <div class="author-image">IF</div>
276
- <div>
277
- <p style="margin: 0; font-weight: 600; color: #1f2937;">Ivy Fiecas-Borjal</p>
278
- <p style="margin: 0; font-size: 14px; color: #6b7280;">Builder of AI/ML Experiences | Business Dev in Tech</p>
279
- <p style="margin-top: 5px; font-size: 14px;">
280
- <a href="https://ifiecas.com/" target="_blank" style="color: #2563eb;">Visit Portfolio</a>
281
- </p>
282
- </div>
283
- </div>
284
- """, unsafe_allow_html=True)
285
-
286
- # Personal note
287
- st.markdown("""
288
- <p class="about-text">
289
- This app was created as part of a predictive analytics class at Victoria University (Melbourne) under Dr. Omid Ameri Sianaki.
290
- It was a fun and insightful learning experience!
291
- </p>
292
- """, unsafe_allow_html=True)
293
-
294
- # Final disclaimer
295
- st.markdown("""<div class="footer-disclaimer">
296
- <p><strong>Educational Project Disclaimer:</strong> This application is a prototype created for demonstration purposes only.
297
- It is not affiliated with any real bank or financial institution.</p>
298
- <p>© 2025 SmartLoanAI – A Machine Learning Showcase Project</p>
299
- </div>""", unsafe_allow_html=True)
300
-
301
  st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
3
  import numpy as np
4
  from huggingface_hub import hf_hub_download
5
 
6
+ # Page configuration
7
  st.set_page_config(
8
  page_title="Loan Approval System",
9
  page_icon="🏦",
10
+ layout="centered",
11
  initial_sidebar_state="collapsed"
12
  )
13
 
14
+ # Custom CSS for styling with the specified color theme
15
+ st.markdown("""
16
+ <style>
17
+ /* Color Theme */
18
+ :root {
19
+ --primary-purple: #7950F2;
20
+ --primary-purple-light: #9775F3;
21
+ --primary-purple-dark: #5F3DC4;
22
+ --complementary-orange: #FF5E3A;
23
+ --complementary-orange-light: #FF8A6C;
24
+ --light-gray: #F8F9FA;
25
+ --dark-gray: #343A40;
26
+ }
27
+
28
+ /* Main containers */
29
+ .main .block-container {
30
+ padding: 2rem;
31
+ border-radius: 10px;
32
+ background-color: white;
33
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
34
+ }
35
+
36
+ /* Font family - applied globally */
37
+ * {
38
+ font-family: 'Helvetica', 'Arial', sans-serif !important;
39
+ }
40
+
41
+ /* Specific selectors to ensure Helvetica is applied everywhere */
42
+ body, .stMarkdown, p, h1, h2, h3, h4, h5, h6, .stButton, .stSelectbox, .stNumberInput,
43
+ .stTextInput, div, span, .streamlit-container, .stAlert, .stText, button, input, select,
44
+ textarea, .streamlit-expanderHeader, .streamlit-expanderContent {
45
+ font-family: 'Helvetica', 'Arial', sans-serif !important;
46
+ }
47
+
48
+ /* Headers */
49
+ h1, h2, h3 {
50
+ color: var(--primary-purple-dark);
51
+ }
52
+
53
+ /* Custom cards for sections */
54
+ .section-card {
55
+ background-color: var(--light-gray);
56
+ border-radius: 8px;
57
+ padding: 1.5rem;
58
+ margin-bottom: 1.5rem;
59
+ border-left: 4px solid var(--primary-purple);
60
+ }
61
+
62
+ /* Remove purple left border from the first section card */
63
+ .remove-border {
64
+ border-left: none !important;
65
+ }
66
+
67
+ /* Button styling */
68
+ .stButton > button {
69
+ background-color: var(--primary-purple);
70
+ color: white;
71
+ border: none;
72
+ border-radius: 5px;
73
+ padding: 0.5rem 1rem;
74
+ font-weight: bold;
75
+ width: 100%;
76
+ transition: all 0.3s;
77
+ }
78
+ .stButton > button:hover {
79
+ background-color: var(--primary-purple-dark);
80
+ transform: translateY(-2px);
81
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
82
+ }
83
+
84
+ /* Result styling */
85
+ .result-approved {
86
+ background-color: #E8F5E9;
87
+ border-left: 4px solid #4CAF50;
88
+ padding: 1rem;
89
+ border-radius: 5px;
90
+ margin-top: 1rem;
91
+ }
92
+ .result-rejected {
93
+ background-color: #FFEBEE;
94
+ border-left: 4px solid #F44336;
95
+ padding: 1rem;
96
+ border-radius: 5px;
97
+ margin-top: 1rem;
98
+ }
99
+
100
+ /* Input widgets */
101
+ .stNumberInput, .stSelectbox {
102
+ margin-bottom: 1rem;
103
+ }
104
+
105
+ /* Footer */
106
+ .footer {
107
+ text-align: center;
108
+ margin-top: 2rem;
109
+ padding-top: 1rem;
110
+ border-top: 1px solid #EEEEEE;
111
+ font-size: 0.8rem;
112
+ color: #666666;
113
+ }
114
+
115
+ /* Divider */
116
+ .divider {
117
+ border-top: 1px solid #EEEEEE;
118
+ margin: 1.5rem 0;
119
+ }
120
+
121
+ /* Badge */
122
+ .badge {
123
+ display: inline-block;
124
+ background-color: var(--complementary-orange);
125
+ color: white;
126
+ padding: 0.25rem 0.5rem;
127
+ border-radius: 4px;
128
+ font-size: 0.8rem;
129
+ margin-left: 0.5rem;
130
+ }
131
+
132
+ /* Banner image styling */
133
+ .banner-image {
134
+ width: 100%;
135
+ margin-bottom: 1.5rem;
136
+ border-radius: 10px;
137
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
138
+ }
139
+
140
+ /* Footer disclaimer */
141
+ .footer-disclaimer {
142
+ text-align: center;
143
+ margin-top: 2rem;
144
+ padding: 1rem;
145
+ border-top: 1px solid #EEEEEE;
146
+ font-size: 0.9rem;
147
+ color: #666666;
148
+ line-height: 1.5;
149
+ background-color: var(--light-gray);
150
+ border-radius: 5px;
151
+ }
152
+ </style>
153
+ """, unsafe_allow_html=True)
154
+
155
+ # App header with banner image instead of title
156
+ st.markdown('<img src="https://i.postimg.cc/R0gGW9kb/ACTION-PLAN.png" class="banner-image" alt="SmartLoanAI Banner">', unsafe_allow_html=True)
157
 
158
+ # Load the trained model from Hugging Face
159
  @st.cache_resource
160
  def load_model():
161
  model_path = hf_hub_download(repo_id="ifiecas/LoanApproval-DT-v1.0", filename="best_pruned_dt.pkl")
 
163
 
164
  model = load_model()
165
 
166
+ # Initialize session state for restart functionality
167
+ if 'restart_clicked' not in st.session_state:
168
+ st.session_state.restart_clicked = False
169
 
170
+ # Create tabs for better organization
171
+ tab1, tab2 = st.tabs(["Loan Application", "About the System"])
 
 
 
 
 
 
 
 
 
172
 
173
+ with tab1:
174
+ # Reset all form values if restart was clicked
175
+ if st.session_state.restart_clicked:
176
+ st.session_state.restart_clicked = False # Reset flag
177
+
178
+ # Personal Information Section
179
+ st.markdown('<div class="section-card"><h3>Personal Information</h3>', unsafe_allow_html=True)
180
+
181
+ col1, col2 = st.columns(2)
 
 
 
 
 
182
  with col1:
183
  gender = st.selectbox("Gender", ["Male", "Female"])
184
+ education = st.selectbox("Education Level", ["Graduate", "Under Graduate"])
185
+
186
  with col2:
187
  marital_status = st.selectbox("Marital Status", ["Married", "Not Married"])
188
+ number_of_dependents = st.number_input("Number of Dependents", min_value=0, max_value=10, value=0)
189
+
190
+ self_employed = st.selectbox("Self-Employed", ["No", "Yes"])
 
191
  st.markdown('</div>', unsafe_allow_html=True)
192
+
193
+ # Financial Details Section
194
+ st.markdown('<div class="section-card"><h3>Financial Details</h3>', unsafe_allow_html=True)
195
+
196
+ col1, col2 = st.columns(2)
197
  with col1:
198
  applicant_income = st.number_input("Monthly Income ($)", min_value=0, value=5000)
199
+ loan_amount = st.number_input("Loan Amount ($)", min_value=0, value=100000)
200
  credit_history = st.selectbox("Credit History Status", [1, 0],
201
+ format_func=lambda x: "No existing unsettled loans (1)" if x == 1 else "Have unsettled loans (0)")
202
+
203
  with col2:
204
  coapplicant_income = st.number_input("Co-Applicant's Income ($)", min_value=0)
 
 
 
 
205
  loan_term = st.slider("Loan Term (months)", min_value=12, max_value=360, value=180, step=12)
206
+ location = st.selectbox("Property Location", ["Urban", "Semiurban", "Rural"])
207
+
208
  st.markdown('</div>', unsafe_allow_html=True)
209
+
210
+ # Summary section - without DTI Assessment or Eligibility Check
211
+ st.markdown('<div class="section-card"><h3>Application Summary</h3>', unsafe_allow_html=True)
212
+
213
  total_income = applicant_income + coapplicant_income
214
+
215
+ # Calculate monthly payment (simplified calculation)
216
+ interest_rate = 0.05 # Assuming 5% annual interest rate
217
  monthly_interest = interest_rate / 12
218
  num_payments = loan_term
219
+
220
+ # Monthly payment using the loan amortization formula
221
  if monthly_interest == 0 or num_payments == 0:
222
  monthly_payment = 0
223
  else:
224
  monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \
225
+ ((1 + monthly_interest) ** num_payments - 1)
226
+
227
+ # Calculate DTI for backend use only (not displayed)
228
+ dti = (monthly_payment / total_income) if total_income > 0 else 0
229
+ dti_percent = dti * 100
230
+
231
+ # Display summary metrics
232
+ col1, col2, col3 = st.columns(3)
233
+ col1.metric("Total Monthly Income", f"${total_income:,}")
234
+ col2.metric("Estimated Monthly Payment", f"${monthly_payment:.2f}")
235
+ col3.metric("Loan Term", f"{loan_term//12} years")
236
+
237
+ # Add interest rate disclaimer
238
+ st.markdown(f"""
239
+ <div style="font-size: 0.8rem; color: #666; margin-top: -10px; margin-bottom: 20px;">
240
+ * Estimated payment based on {interest_rate*100:.1f}% annual interest rate. Actual rates may vary.
241
+ </div>
242
+ """, unsafe_allow_html=True)
243
+
244
  st.markdown('</div>', unsafe_allow_html=True)
245
+
246
+ # Prediction and restart buttons
247
+ col1, col2 = st.columns([3, 1])
248
+
249
+ with col1:
250
+ predict_button = st.button("Check Loan Approval Status", use_container_width=True)
251
+
252
+ with col2:
253
+ restart_button = st.button("🔄 Restart", use_container_width=True,
254
+ help="Reset all form fields and start over")
255
+
256
+ # Handle restart button click
257
+ if restart_button:
258
  st.session_state.restart_clicked = True
259
+ st.rerun() # Using st.rerun() instead of st.experimental_rerun()
260
+
261
+ def preprocess_input():
262
+ # Convert categorical inputs to numerical format based on encoding reference
263
  gender_num = 0 if gender == "Male" else 1
264
+ marital_status_num = 0 if marital_status == "Not Married" else 1
265
+ education_num = 0 if education == "Under Graduate" else 1
266
+ self_employed_num = 0 if self_employed == "No" else 1
267
+ credit_history_num = credit_history # Already numerical (0,1)
268
+
269
+ # One-Hot Encoding for Location
270
  location_semiurban = 1 if location == "Semiurban" else 0
271
  location_urban = 1 if location == "Urban" else 0
272
+
273
+ # Convert Term from months to years
274
  term_years = loan_term / 12
275
+
276
+ # Compute Derived Features - use the same monthly payment calculated above
277
+ debt_to_income = monthly_payment / total_income if total_income > 0 else 0
278
+ credit_amount_interaction = loan_amount * credit_history_num # Interaction effect
279
+ income_term_ratio = total_income / term_years if term_years > 0 else 0 # Avoid divide by zero
280
+
281
+ # Return array with all 16 features
282
  return np.array([[
283
  gender_num, marital_status_num, number_of_dependents, education_num, self_employed_num,
284
  applicant_income, coapplicant_income, loan_amount, credit_history_num,
285
+ total_income, debt_to_income, location_semiurban, location_urban, term_years,
286
+ credit_amount_interaction, income_term_ratio
287
  ]])
288
+
289
+ # Display prediction
290
+ if predict_button:
291
+ with st.spinner("Processing your application..."):
292
+ input_data = preprocess_input()
293
+ prediction = model.predict(input_data)
294
+
295
+ # Apply additional rules to override the model in certain cases (backend only)
296
+ manual_rejection = False
297
+
298
+ # Rule-based rejections that override the model (but don't show to user)
299
  if total_income < 1500:
300
+ manual_rejection = True
301
+ elif dti_percent > 50:
302
+ manual_rejection = True
303
+ elif credit_history == 0 and dti_percent > 35:
304
+ manual_rejection = True
305
+
306
+ # Final decision combines model prediction and manual eligibility checks
307
+ final_approval = (prediction[0] == 1) and not manual_rejection
308
+
309
+ # Show result with enhanced styling
310
+ if final_approval:
 
 
311
  st.markdown("""
312
  <div class="result-approved">
313
  <h3 style="color: #2E7D32;">✅ Loan Approved</h3>
314
+ <p>Congratulations! Based on your information, you're eligible for this loan.</p>
 
 
 
 
 
 
315
  </div>
316
  """, unsafe_allow_html=True)
317
  else:
318
+ st.markdown("""
319
  <div class="result-rejected">
320
  <h3 style="color: #C62828;">❌ Loan Not Approved</h3>
321
+ <p>Unfortunately, based on your current information, we cannot approve your loan application.</p>
322
+ <p>Consider improving your credit score, reducing existing debt, or applying with a co-applicant with higher income.</p>
 
 
 
 
 
 
 
323
  </div>
324
  """, unsafe_allow_html=True)
325
 
326
+ with tab2:
327
+ # Add custom CSS for better styling
328
+ st.markdown("""
329
+ <style>
330
+ /* Main container styling */
331
+ .about-container {
332
+ background-color: #f8f9fa;
333
+ border-radius: 10px;
334
+ padding: 20px;
335
+ margin-bottom: 20px;
336
+ }
337
+
338
+ /* Section styling */
339
+ .about-section {
340
+ margin-bottom: 25px;
341
+ }
342
+
343
+ /* Section headers */
344
+ .section-header {
345
+ color: #1e3a8a;
346
+ font-size: 20px;
347
+ font-weight: 600;
348
+ margin-bottom: 10px;
349
+ border-bottom: 2px solid #e5e7eb;
350
+ padding-bottom: 5px;
351
+ }
352
+
353
+ /* Regular text */
354
+ .about-text {
355
+ font-size: 16px;
356
+ line-height: 1.6;
357
+ color: #374151;
358
+ }
359
+
360
+ /* Metrics card container */
361
+ .metrics-container {
362
+ display: flex;
363
+ flex-wrap: wrap;
364
+ gap: 15px;
365
+ margin: 15px 0;
366
+ }
367
+
368
+ /* Individual metric card */
369
+ .metric-card {
370
+ background-color: white;
371
+ border-radius: 8px;
372
+ padding: 15px;
373
+ min-width: 120px;
374
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
375
+ flex: 1;
376
+ text-align: center;
377
+ }
378
+
379
+ /* Metric value */
380
+ .metric-value {
381
+ font-size: 22px;
382
+ font-weight: 600;
383
+ color: #2563eb;
384
+ }
385
+
386
+ /* Metric label */
387
+ .metric-label {
388
+ font-size: 14px;
389
+ color: #6b7280;
390
+ margin-top: 5px;
391
+ }
392
+
393
+ /* Footer styling */
394
+ .footer-disclaimer {
395
+ background-color: #f3f4f6;
396
+ border-radius: 8px;
397
+ padding: 15px;
398
+ margin-top: 30px;
399
+ border-left: 4px solid #9ca3af;
400
+ font-size: 14px;
401
+ color: #4b5563;
402
+ }
403
+
404
+ /* Author bio section */
405
+ .author-bio {
406
+ display: flex;
407
+ align-items: center;
408
+ gap: 15px;
409
+ background-color: white;
410
+ border-radius: 8px;
411
+ padding: 15px;
412
+ margin: 20px 0;
413
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
414
+ }
415
+
416
+ /* Author image placeholder */
417
+ .author-image {
418
+ width: 60px;
419
+ height: 60px;
420
+ border-radius: 50%;
421
+ background-color: #e5e7eb;
422
+ display: flex;
423
+ align-items: center;
424
+ justify-content: center;
425
+ color: #9ca3af;
426
+ font-size: 20px;
427
+ font-weight: bold;
428
+ }
429
+ </style>
430
+ """, unsafe_allow_html=True)
431
 
432
+ # Main content container
433
  st.markdown('<div class="about-container">', unsafe_allow_html=True)
434
+
435
+ # System overview section
436
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
437
  st.markdown('<h2 class="section-header">About the Loan Approval System</h2>', unsafe_allow_html=True)
438
+ st.markdown(
439
+ '<p class="about-text">Our AI-powered system evaluates loan applications using machine learning and '
440
+ 'industry-standard criteria. It analyzes your financial information, credit history, and loan requirements '
441
+ 'to provide fast, objective loan decisions.</p>', unsafe_allow_html=True
442
+ )
 
443
  st.markdown('</div>', unsafe_allow_html=True)
444
+
445
+ # Model information section
446
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
447
+ st.markdown('<h2 class="section-header">About the ML Model</h2>', unsafe_allow_html=True)
448
+ st.markdown(
449
+ '<p class="about-text">The machine learning model powering this system is a Decision Tree classifier, '
450
+ 'which outperformed several alternatives including KNN, Random Forest, Logistic Regression, and Support '
451
+ 'Vector Machine in our testing phase. The model was refined using Cost Complexity Pruning (CCP) to identify '
452
+ 'the optimal alpha value, preventing overfitting while maintaining high predictive accuracy.</p>',
453
+ unsafe_allow_html=True
454
+ )
455
  st.markdown('</div>', unsafe_allow_html=True)
456
+
457
+ # Performance metrics section with cards
458
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
459
+ st.markdown('<h2 class="section-header">Model Performance Metrics</h2>', unsafe_allow_html=True)
460
+
461
+ # Metrics cards using HTML for better styling
462
+ st.markdown(
463
+ '<div class="metrics-container">'
464
+ ' <div class="metric-card">'
465
+ ' <div class="metric-value">83.61%</div>'
466
+ ' <div class="metric-label">Accuracy</div>'
467
+ ' </div>'
468
+ ' <div class="metric-card">'
469
+ ' <div class="metric-value">80.77%</div>'
470
+ ' <div class="metric-label">Precision</div>'
471
+ ' </div>'
472
+ ' <div class="metric-card">'
473
+ ' <div class="metric-value">100.00%</div>'
474
+ ' <div class="metric-label">Recall</div>'
475
+ ' </div>'
476
+ ' <div class="metric-card">'
477
+ ' <div class="metric-value">89.36%</div>'
478
+ ' <div class="metric-label">F1 Score</div>'
479
+ ' </div>'
480
+ '</div>',
481
+ unsafe_allow_html=True
482
+ )
483
+
484
+ # Link to documentation/more info
485
+ st.markdown(
486
+ '<p class="about-text">For more information about the modeling process (from loading the dataset to fine-tuning '
487
+ 'the model), check here: <a href="https://github.com/ifiecas/bankloan2" target="_blank" style="color: #2563eb;">Github</a></p>',
488
+ unsafe_allow_html=True
489
+ )
490
+
491
+ # YouTube video section
492
+ st.markdown('<h2 class="section-header">Brief Explanation</h2>', unsafe_allow_html=True)
493
+ st.markdown('<p class="about-text">Watch this video for a brief explanation of the assessment:</p>', unsafe_allow_html=True)
494
+
495
+ # YouTube embed with responsive container
496
  st.markdown("""
497
+ <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;">
498
+ <iframe
499
+ style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
500
+ src="https://www.youtube.com/embed/y88GidhkAE8?si=iesfB084u4qrtPB_"
501
+ title="Assessment Explanation"
502
+ frameborder="0"
503
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
504
+ allowfullscreen>
505
+ </iframe>
506
+ </div>
507
  """, unsafe_allow_html=True)
508
+
509
+ st.markdown('</div>', unsafe_allow_html=True)
510
+
511
+ # Author section with profile
512
  st.markdown('<div class="about-section">', unsafe_allow_html=True)
513
+ st.markdown('<h2 class="section-header">Behind the Build</h2>', unsafe_allow_html=True)
514
+
515
+ st.markdown(
516
+ '<div class="author-bio">'
517
+ ' <div class="author-image">IF</div>'
518
+ ' <div>'
519
+ ' <p style="margin: 0; font-weight: 600; color: #1f2937;">Ivy Fiecas-Borjal</p>'
520
+ ' <p style="margin: 0; font-size: 14px; color: #6b7280;">Building with AI & ML | Biz Dev in Tech</p>'
521
+ ' <p style="margin-top: 5px; font-size: 14px;">'
522
+ ' <a href="https://ifiecas.com/" target="_blank" style="color: #2563eb; text-decoration: none;">Visit Portfolio</a>'
523
+ ' </p>'
524
+ ' </div>'
525
+ '</div>',
526
+ unsafe_allow_html=True
527
+ )
528
+
529
+ st.markdown(
530
+ '<p class="about-text">Inspired by an assessment in BCO6008 Predictive Analytics class in Victoria University '
531
+ '(Melbourne) with Dr. Omid Ameri Sianaki. Enjoyed doing this and learned a lot! 😊</p>',
532
+ unsafe_allow_html=True
533
+ )
 
 
 
 
 
 
 
 
534
  st.markdown('</div>', unsafe_allow_html=True)
535
+
536
+ # Disclaimer footer
537
+ st.markdown("""<div class="footer-disclaimer">
538
+ <p><strong>Educational Project Disclaimer:</strong> This application is a prototype created to demonstrate machine learning model deployment and is not an actual financial service. The loan approval decisions are based on a trained model for educational purposes only and should not be used for real financial decisions.</p>
539
+ <p>© 2025 SmartLoanAI - Machine Learning Showcase Project</p>
540
+ </div>""", unsafe_allow_html=True)