Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -3,244 +3,19 @@ import joblib
|
|
3 |
import numpy as np
|
4 |
from huggingface_hub import hf_hub_download
|
5 |
|
6 |
-
# Page
|
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
|
15 |
-
|
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 |
-
max-width: 1200px;
|
35 |
-
margin: 0 auto;
|
36 |
-
}
|
37 |
-
|
38 |
-
/* Font family - applied globally */
|
39 |
-
* {
|
40 |
-
font-family: 'Helvetica', 'Arial', sans-serif !important;
|
41 |
-
}
|
42 |
-
|
43 |
-
/* Specific selectors to ensure Helvetica is applied everywhere */
|
44 |
-
body, .stMarkdown, p, h1, h2, h3, h4, h5, h6, .stButton, .stSelectbox, .stNumberInput,
|
45 |
-
.stTextInput, div, span, .streamlit-container, .stAlert, .stText, button, input, select,
|
46 |
-
textarea, .streamlit-expanderHeader, .streamlit-expanderContent {
|
47 |
-
font-family: 'Helvetica', 'Arial', sans-serif !important;
|
48 |
-
}
|
49 |
-
|
50 |
-
/* Headers */
|
51 |
-
h1, h2, h3 {
|
52 |
-
color: var(--primary-purple-dark);
|
53 |
-
}
|
54 |
-
|
55 |
-
/* Custom cards for sections */
|
56 |
-
.section-card {
|
57 |
-
background-color: var(--light-gray);
|
58 |
-
border-radius: 8px;
|
59 |
-
padding: 1.5rem;
|
60 |
-
margin-bottom: 1.5rem;
|
61 |
-
border-left: 4px solid var(--primary-purple);
|
62 |
-
transition: all 0.3s ease;
|
63 |
-
}
|
64 |
-
|
65 |
-
.section-card:hover {
|
66 |
-
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.08);
|
67 |
-
transform: translateY(-2px);
|
68 |
-
}
|
69 |
-
|
70 |
-
/* Remove purple left border from the first section card */
|
71 |
-
.remove-border {
|
72 |
-
border-left: none !important;
|
73 |
-
}
|
74 |
-
|
75 |
-
/* Button styling */
|
76 |
-
.stButton > button {
|
77 |
-
background-color: var(--primary-purple);
|
78 |
-
color: white;
|
79 |
-
border: none;
|
80 |
-
border-radius: 5px;
|
81 |
-
padding: 0.5rem 1rem;
|
82 |
-
font-weight: bold;
|
83 |
-
width: 100%;
|
84 |
-
transition: all 0.3s;
|
85 |
-
}
|
86 |
-
.stButton > button:hover {
|
87 |
-
background-color: var(--primary-purple-dark);
|
88 |
-
transform: translateY(-2px);
|
89 |
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
90 |
-
}
|
91 |
-
|
92 |
-
/* Result styling */
|
93 |
-
.result-approved {
|
94 |
-
background-color: #E8F5E9;
|
95 |
-
border-left: 4px solid #4CAF50;
|
96 |
-
padding: 1.5rem;
|
97 |
-
border-radius: 5px;
|
98 |
-
margin-top: 1.5rem;
|
99 |
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
100 |
-
transition: all 0.3s ease;
|
101 |
-
}
|
102 |
-
.result-rejected {
|
103 |
-
background-color: #FFEBEE;
|
104 |
-
border-left: 4px solid #F44336;
|
105 |
-
padding: 1.5rem;
|
106 |
-
border-radius: 5px;
|
107 |
-
margin-top: 1.5rem;
|
108 |
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
109 |
-
transition: all 0.3s ease;
|
110 |
-
}
|
111 |
-
|
112 |
-
/* Input widgets */
|
113 |
-
.stNumberInput, .stSelectbox {
|
114 |
-
margin-bottom: 1rem;
|
115 |
-
}
|
116 |
-
|
117 |
-
/* Footer */
|
118 |
-
.footer {
|
119 |
-
text-align: center;
|
120 |
-
margin-top: 2rem;
|
121 |
-
padding-top: 1rem;
|
122 |
-
border-top: 1px solid #EEEEEE;
|
123 |
-
font-size: 0.8rem;
|
124 |
-
color: #666666;
|
125 |
-
}
|
126 |
-
|
127 |
-
/* Divider */
|
128 |
-
.divider {
|
129 |
-
border-top: 1px solid #EEEEEE;
|
130 |
-
margin: 1.5rem 0;
|
131 |
-
}
|
132 |
-
|
133 |
-
/* Badge */
|
134 |
-
.badge {
|
135 |
-
display: inline-block;
|
136 |
-
background-color: var(--complementary-orange);
|
137 |
-
color: white;
|
138 |
-
padding: 0.25rem 0.5rem;
|
139 |
-
border-radius: 4px;
|
140 |
-
font-size: 0.8rem;
|
141 |
-
margin-left: 0.5rem;
|
142 |
-
}
|
143 |
-
|
144 |
-
/* Banner image styling */
|
145 |
-
.banner-image {
|
146 |
-
width: 100%;
|
147 |
-
margin-bottom: 1.5rem;
|
148 |
-
border-radius: 10px;
|
149 |
-
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
150 |
-
transition: all 0.3s ease;
|
151 |
-
}
|
152 |
-
|
153 |
-
.banner-image:hover {
|
154 |
-
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
155 |
-
}
|
156 |
-
|
157 |
-
/* Footer disclaimer */
|
158 |
-
.footer-disclaimer {
|
159 |
-
text-align: center;
|
160 |
-
margin-top: 2rem;
|
161 |
-
padding: 1.5rem;
|
162 |
-
border-top: 1px solid #EEEEEE;
|
163 |
-
font-size: 0.9rem;
|
164 |
-
color: #666666;
|
165 |
-
line-height: 1.5;
|
166 |
-
background-color: var(--light-gray);
|
167 |
-
border-radius: 5px;
|
168 |
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
169 |
-
}
|
170 |
-
|
171 |
-
/* Tabs styling */
|
172 |
-
.stTabs [data-baseweb="tab-list"] {
|
173 |
-
gap: 8px;
|
174 |
-
}
|
175 |
-
|
176 |
-
.stTabs [data-baseweb="tab"] {
|
177 |
-
background-color: white;
|
178 |
-
border-radius: 4px 4px 0 0;
|
179 |
-
padding: 10px 16px;
|
180 |
-
height: auto;
|
181 |
-
}
|
182 |
-
|
183 |
-
.stTabs [aria-selected="true"] {
|
184 |
-
background-color: var(--primary-purple-light) !important;
|
185 |
-
color: white !important;
|
186 |
-
font-weight: bold;
|
187 |
-
}
|
188 |
-
|
189 |
-
/* Improved form inputs */
|
190 |
-
div[data-testid="stFormSubmit"] > button {
|
191 |
-
background-color: var(--primary-purple);
|
192 |
-
color: white;
|
193 |
-
}
|
194 |
-
|
195 |
-
/* Tooltip improvements */
|
196 |
-
div[data-baseweb="tooltip"] {
|
197 |
-
background-color: var(--dark-gray);
|
198 |
-
border-radius: 4px;
|
199 |
-
padding: 8px;
|
200 |
-
font-size: 14px;
|
201 |
-
}
|
202 |
-
|
203 |
-
/* Metrics styling */
|
204 |
-
[data-testid="stMetric"] {
|
205 |
-
background-color: white;
|
206 |
-
border-radius: 8px;
|
207 |
-
padding: 1rem;
|
208 |
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
209 |
-
transition: all 0.2s ease;
|
210 |
-
}
|
211 |
-
|
212 |
-
[data-testid="stMetric"]:hover {
|
213 |
-
transform: translateY(-3px);
|
214 |
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
215 |
-
}
|
216 |
-
|
217 |
-
[data-testid="stMetricLabel"] {
|
218 |
-
color: var(--primary-purple-dark);
|
219 |
-
}
|
220 |
-
|
221 |
-
[data-testid="stMetricValue"] {
|
222 |
-
font-weight: bold;
|
223 |
-
font-size: 1.5rem !important;
|
224 |
-
color: var(--primary-purple);
|
225 |
-
}
|
226 |
-
|
227 |
-
/* Animation for loading */
|
228 |
-
@keyframes pulse {
|
229 |
-
0% { opacity: 0.6; }
|
230 |
-
50% { opacity: 1; }
|
231 |
-
100% { opacity: 0.6; }
|
232 |
-
}
|
233 |
-
|
234 |
-
.loading-pulse {
|
235 |
-
animation: pulse 1.5s infinite ease-in-out;
|
236 |
-
}
|
237 |
-
</style>
|
238 |
-
""", unsafe_allow_html=True)
|
239 |
-
|
240 |
-
# App header with banner image instead of title
|
241 |
-
st.markdown('<img src="https://i.postimg.cc/R0gGW9kb/ACTION-PLAN.png" class="banner-image" alt="SmartLoanAI Banner">', unsafe_allow_html=True)
|
242 |
|
243 |
-
# Load
|
244 |
@st.cache_resource
|
245 |
def load_model():
|
246 |
model_path = hf_hub_download(repo_id="ifiecas/LoanApproval-DT-v1.0", filename="best_pruned_dt.pkl")
|
@@ -248,451 +23,279 @@ def load_model():
|
|
248 |
|
249 |
model = load_model()
|
250 |
|
251 |
-
# Initialize session state for restart functionality
|
252 |
-
if 'restart_clicked' not in st.session_state:
|
253 |
-
st.session_state.restart_clicked = False
|
254 |
|
255 |
-
#
|
|
|
|
|
|
|
256 |
st.markdown("""<div class="footer-disclaimer" style="margin-bottom: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107;">
|
257 |
-
<p><strong>Educational Project Disclaimer:</strong> This
|
258 |
</div>""", unsafe_allow_html=True)
|
259 |
|
260 |
-
# Create tabs for better organization
|
261 |
-
tab1, tab2 = st.tabs(["📝 Loan Application", "ℹ️ About the System"])
|
262 |
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
# Introduction text
|
269 |
st.markdown("""
|
270 |
<h2 style="text-align: center; color: var(--primary-purple-dark); margin-bottom: 20px;">
|
271 |
Smart Loan Application System
|
272 |
</h2>
|
273 |
<p style="text-align: center; margin-bottom: 30px; font-size: 1.1rem;">
|
274 |
-
Fill out the form below to check your loan eligibility. Our
|
275 |
</p>
|
276 |
""", unsafe_allow_html=True)
|
277 |
-
|
278 |
-
#
|
279 |
st.markdown('<div class="section-card"><h3>👤 Personal Information</h3>', unsafe_allow_html=True)
|
280 |
-
|
281 |
col1, col2, col3 = st.columns(3)
|
282 |
with col1:
|
283 |
gender = st.selectbox("Gender", ["Male", "Female"])
|
284 |
-
number_of_dependents = st.number_input("Number of Dependents", min_value=0, max_value=10, value=0
|
285 |
-
|
286 |
-
|
287 |
with col2:
|
288 |
marital_status = st.selectbox("Marital Status", ["Married", "Not Married"])
|
289 |
-
self_employed = st.selectbox("Self-Employed", ["No", "Yes"]
|
290 |
-
|
291 |
-
|
292 |
with col3:
|
293 |
-
education = st.selectbox("Education Level", ["Graduate", "Under Graduate"]
|
294 |
-
help="Higher education status of the applicant")
|
295 |
-
|
296 |
st.markdown('</div>', unsafe_allow_html=True)
|
297 |
-
|
298 |
-
# Financial Details Section
|
299 |
st.markdown('<div class="section-card"><h3>💰 Financial Details</h3>', unsafe_allow_html=True)
|
300 |
-
|
301 |
col1, col2, col3 = st.columns(3)
|
302 |
with col1:
|
303 |
-
applicant_income = st.number_input("Monthly Income ($)", min_value=0, value=5000
|
304 |
-
help="Applicant's monthly income in dollars")
|
305 |
credit_history = st.selectbox("Credit History Status", [1, 0],
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
with col2:
|
310 |
-
coapplicant_income = st.number_input("Co-Applicant's Income ($)", min_value=0
|
311 |
-
|
312 |
-
|
313 |
-
help="The location where the property is situated")
|
314 |
-
|
315 |
with col3:
|
316 |
-
loan_amount = st.number_input("Loan Amount ($)", min_value=0, value=100000
|
317 |
-
|
318 |
-
loan_term = st.slider("Loan Term (months)", min_value=12, max_value=360, value=180, step=12,
|
319 |
-
help="Duration of the loan in months")
|
320 |
-
|
321 |
st.markdown('</div>', unsafe_allow_html=True)
|
322 |
-
|
323 |
-
# Summary
|
324 |
-
st.markdown('<div class="section-card"><h3>📊 Application Summary</h3>', unsafe_allow_html=True)
|
325 |
-
|
326 |
total_income = applicant_income + coapplicant_income
|
327 |
-
|
328 |
-
# Calculate monthly payment (simplified calculation)
|
329 |
-
interest_rate = 0.05 # Assuming 5% annual interest rate
|
330 |
monthly_interest = interest_rate / 12
|
331 |
num_payments = loan_term
|
332 |
-
|
333 |
-
# Monthly payment using the loan amortization formula
|
334 |
if monthly_interest == 0 or num_payments == 0:
|
335 |
monthly_payment = 0
|
336 |
else:
|
337 |
monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
col1, col2, col3, col4 = st.columns(4)
|
346 |
-
col1.metric("Total Monthly Income", f"${total_income
|
347 |
-
col2.metric("Estimated Monthly Payment", f"${monthly_payment
|
348 |
-
col3.metric("Loan Term", f"{loan_term//12} years")
|
349 |
-
col4.metric("Debt-to-Income Ratio", f"{
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
st.markdown(f"""
|
355 |
-
<div style="font-size: 0.9rem; color: #666; margin-top: 10px; margin-bottom: 20px; background-color: #f8f9fa; padding: 10px; border-radius: 5px;">
|
356 |
-
<strong>Note:</strong> Estimated payment based on {interest_rate*100:.1f}% annual interest rate. Actual rates may vary based on credit score and market conditions.
|
357 |
-
<br>A healthy debt-to-income ratio is typically below 36%.
|
358 |
-
</div>
|
359 |
-
""", unsafe_allow_html=True)
|
360 |
-
|
361 |
st.markdown('</div>', unsafe_allow_html=True)
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
with
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
# Handle restart button click
|
374 |
-
if restart_button:
|
375 |
st.session_state.restart_clicked = True
|
376 |
st.rerun()
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
gender_num = 0 if gender == "Male" else 1
|
381 |
-
marital_status_num =
|
382 |
-
education_num =
|
383 |
-
self_employed_num =
|
384 |
-
credit_history_num = credit_history
|
385 |
-
|
386 |
-
# One-Hot Encoding for Location
|
387 |
location_semiurban = 1 if location == "Semiurban" else 0
|
388 |
location_urban = 1 if location == "Urban" else 0
|
389 |
-
|
390 |
-
# Convert Term from months to years
|
391 |
term_years = loan_term / 12
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
credit_amount_interaction = loan_amount * credit_history_num # Interaction effect
|
396 |
-
income_term_ratio = total_income / term_years if term_years > 0 else 0 # Avoid divide by zero
|
397 |
-
|
398 |
-
# Return array with all 16 features
|
399 |
return np.array([[
|
400 |
gender_num, marital_status_num, number_of_dependents, education_num, self_employed_num,
|
401 |
applicant_income, coapplicant_income, loan_amount, credit_history_num,
|
402 |
-
total_income,
|
403 |
-
|
404 |
]])
|
405 |
-
|
406 |
-
#
|
407 |
-
if
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
prediction = model.predict(input_data)
|
417 |
-
|
418 |
-
# Apply additional rules to override the model in certain cases (backend only)
|
419 |
-
manual_rejection = False
|
420 |
-
rejection_reason = ""
|
421 |
-
|
422 |
-
# Rule-based rejections that override the model
|
423 |
if total_income < 1500:
|
424 |
-
|
425 |
-
|
426 |
-
elif
|
427 |
-
|
428 |
-
|
429 |
-
elif credit_history == 0 and
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
if final_approval:
|
438 |
st.markdown("""
|
439 |
<div class="result-approved">
|
440 |
-
<h3 style="color: #2E7D32;
|
441 |
-
<p
|
442 |
-
<p>Our AI model has determined that your application meets our criteria for approval. Here's what happens next:</p>
|
443 |
<ol>
|
444 |
-
<li>Verification of
|
445 |
-
<li>
|
446 |
-
<li>
|
447 |
</ol>
|
448 |
-
<p><em>
|
449 |
</div>
|
450 |
""", unsafe_allow_html=True)
|
451 |
else:
|
452 |
st.markdown(f"""
|
453 |
<div class="result-rejected">
|
454 |
-
<h3 style="color: #C62828;
|
455 |
-
<p
|
456 |
-
<p><strong>
|
457 |
-
<
|
458 |
-
<li>{rejection_reason if rejection_reason else "The combination of factors in your application does not meet our current criteria"}</li>
|
459 |
-
<li>Income to loan amount ratio may be insufficient</li>
|
460 |
-
<li>Credit history concerns</li>
|
461 |
-
</ul>
|
462 |
-
<p><strong>Suggestions for improvement:</strong></p>
|
463 |
<ul>
|
464 |
-
<li>
|
465 |
-
<li>
|
466 |
-
<li>
|
467 |
-
<li>
|
468 |
</ul>
|
469 |
</div>
|
470 |
""", unsafe_allow_html=True)
|
471 |
-
|
472 |
-
# Add disclaimer at the bottom of tab1 as well
|
473 |
-
st.markdown("""<div class="footer-disclaimer">
|
474 |
-
<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>
|
475 |
-
<p>© 2025 SmartLoanAI - Machine Learning Showcase Project</p>
|
476 |
-
</div>""", unsafe_allow_html=True)
|
477 |
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
<style>
|
482 |
-
/* Make all text in the About tab the same size */
|
483 |
-
[data-testid="stAppViewContainer"] .stTabs [aria-label="About the System"] p,
|
484 |
-
[data-testid="stAppViewContainer"] .stTabs [aria-label="About the System"] li {
|
485 |
-
font-size: 16px !important;
|
486 |
-
line-height: 1.5 !important;
|
487 |
-
}
|
488 |
-
|
489 |
-
/* Main container styling */
|
490 |
-
.about-container {
|
491 |
-
background-color: #f8f9fa;
|
492 |
-
border-radius: 10px;
|
493 |
-
padding: 20px;
|
494 |
-
margin-bottom: 20px;
|
495 |
-
}
|
496 |
-
|
497 |
-
/* Section styling */
|
498 |
-
.about-section {
|
499 |
-
margin-bottom: 25px;
|
500 |
-
}
|
501 |
-
|
502 |
-
/* Section headers */
|
503 |
-
.section-header {
|
504 |
-
color: #1e3a8a;
|
505 |
-
font-size: 20px;
|
506 |
-
font-weight: 600;
|
507 |
-
margin-bottom: 10px;
|
508 |
-
border-bottom: 2px solid #e5e7eb;
|
509 |
-
padding-bottom: 5px;
|
510 |
-
}
|
511 |
-
|
512 |
-
/* Regular text */
|
513 |
-
.about-text {
|
514 |
-
font-size: 16px;
|
515 |
-
line-height: 1.6;
|
516 |
-
color: #374151;
|
517 |
-
}
|
518 |
-
|
519 |
-
/* Metrics card container */
|
520 |
-
.metrics-container {
|
521 |
-
display: flex;
|
522 |
-
flex-wrap: wrap;
|
523 |
-
gap: 15px;
|
524 |
-
margin: 15px 0;
|
525 |
-
}
|
526 |
-
|
527 |
-
/* Individual metric card */
|
528 |
-
.metric-card {
|
529 |
-
background-color: white;
|
530 |
-
border-radius: 8px;
|
531 |
-
padding: 15px;
|
532 |
-
min-width: 120px;
|
533 |
-
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
534 |
-
flex: 1;
|
535 |
-
text-align: center;
|
536 |
-
}
|
537 |
-
|
538 |
-
/* Metric value */
|
539 |
-
.metric-value {
|
540 |
-
font-size: 22px;
|
541 |
-
font-weight: 600;
|
542 |
-
color: #2563eb;
|
543 |
-
}
|
544 |
-
|
545 |
-
/* Metric label */
|
546 |
-
.metric-label {
|
547 |
-
font-size: 14px;
|
548 |
-
color: #6b7280;
|
549 |
-
margin-top: 5px;
|
550 |
-
}
|
551 |
-
|
552 |
-
/* Footer styling */
|
553 |
-
.footer-disclaimer {
|
554 |
-
background-color: #f3f4f6;
|
555 |
-
border-radius: 8px;
|
556 |
-
padding: 15px;
|
557 |
-
margin-top: 30px;
|
558 |
-
border-left: 4px solid #9ca3af;
|
559 |
-
font-size: 14px;
|
560 |
-
color: #4b5563;
|
561 |
-
}
|
562 |
-
|
563 |
-
/* Author bio section */
|
564 |
-
.author-bio {
|
565 |
-
display: flex;
|
566 |
-
align-items: center;
|
567 |
-
gap: 15px;
|
568 |
-
background-color: white;
|
569 |
-
border-radius: 8px;
|
570 |
-
padding: 15px;
|
571 |
-
margin: 20px 0;
|
572 |
-
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
573 |
-
}
|
574 |
-
|
575 |
-
/* Author image placeholder */
|
576 |
-
.author-image {
|
577 |
-
width: 60px;
|
578 |
-
height: 60px;
|
579 |
-
border-radius: 50%;
|
580 |
-
background-color: #e5e7eb;
|
581 |
-
display: flex;
|
582 |
-
align-items: center;
|
583 |
-
justify-content: center;
|
584 |
-
color: #9ca3af;
|
585 |
-
font-size: 20px;
|
586 |
-
font-weight: bold;
|
587 |
-
}
|
588 |
-
</style>
|
589 |
-
""", unsafe_allow_html=True)
|
590 |
|
591 |
-
#
|
592 |
st.markdown('<div class="about-container">', unsafe_allow_html=True)
|
593 |
-
|
594 |
-
# System
|
595 |
st.markdown('<div class="about-section">', unsafe_allow_html=True)
|
596 |
st.markdown('<h2 class="section-header">About the Loan Approval System</h2>', unsafe_allow_html=True)
|
597 |
-
st.markdown(
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
|
|
602 |
st.markdown('</div>', unsafe_allow_html=True)
|
603 |
-
|
604 |
-
# Model
|
605 |
st.markdown('<div class="about-section">', unsafe_allow_html=True)
|
606 |
-
st.markdown('<h2 class="section-header">
|
607 |
-
st.markdown(
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
)
|
614 |
st.markdown('</div>', unsafe_allow_html=True)
|
615 |
-
|
616 |
-
# Performance
|
617 |
st.markdown('<div class="about-section">', unsafe_allow_html=True)
|
618 |
-
st.markdown('<h2 class="section-header">Model Performance
|
619 |
-
|
620 |
-
# Metrics cards using HTML for better styling
|
621 |
-
st.markdown(
|
622 |
-
'<div class="metrics-container">'
|
623 |
-
' <div class="metric-card">'
|
624 |
-
' <div class="metric-value">83.61%</div>'
|
625 |
-
' <div class="metric-label">Accuracy</div>'
|
626 |
-
' </div>'
|
627 |
-
' <div class="metric-card">'
|
628 |
-
' <div class="metric-value">80.77%</div>'
|
629 |
-
' <div class="metric-label">Precision</div>'
|
630 |
-
' </div>'
|
631 |
-
' <div class="metric-card">'
|
632 |
-
' <div class="metric-value">100.00%</div>'
|
633 |
-
' <div class="metric-label">Recall</div>'
|
634 |
-
' </div>'
|
635 |
-
' <div class="metric-card">'
|
636 |
-
' <div class="metric-value">89.36%</div>'
|
637 |
-
' <div class="metric-label">F1 Score</div>'
|
638 |
-
' </div>'
|
639 |
-
'</div>',
|
640 |
-
unsafe_allow_html=True
|
641 |
-
)
|
642 |
-
|
643 |
-
# Link to documentation/more info
|
644 |
-
st.markdown(
|
645 |
-
'<p class="about-text">For more information about the modeling process (from loading the dataset to fine-tuning '
|
646 |
-
'the model), check here: <a href="https://github.com/ifiecas/bankloan2" target="_blank" style="color: #2563eb;">https://github.com/ifiecas/bankloan2</a></p>',
|
647 |
-
unsafe_allow_html=True
|
648 |
-
)
|
649 |
-
|
650 |
-
# YouTube video section
|
651 |
-
st.markdown('<h2 class="section-header">Brief Explanation</h2>', unsafe_allow_html=True)
|
652 |
-
st.markdown('<p class="about-text">Watch this video for a brief explanation of the assessment:</p>', unsafe_allow_html=True)
|
653 |
-
|
654 |
-
# YouTube embed with responsive container
|
655 |
st.markdown("""
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
666 |
""", unsafe_allow_html=True)
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
671 |
st.markdown('<div class="about-section">', unsafe_allow_html=True)
|
672 |
-
st.markdown('<h2 class="section-header">
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
unsafe_allow_html=True
|
686 |
-
)
|
687 |
-
|
688 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
689 |
|
|
|
|
|
|
|
|
|
|
|
|
|
690 |
|
691 |
-
st.markdown('<p class="about-text">Inspired by an assessment in BCO6008 Predictive Analytics class in Victoria University (Melbourne) with Dr. Omid Ameri Sianaki. Enjoyed doing this and learned a lot! 😊</p>', unsafe_allow_html=True)
|
692 |
st.markdown('</div>', unsafe_allow_html=True)
|
693 |
-
|
694 |
-
# Disclaimer footer
|
695 |
-
st.markdown("""<div class="footer-disclaimer">
|
696 |
-
<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>
|
697 |
-
<p>© 2025 SmartLoanAI - Machine Learning Showcase Project</p>
|
698 |
-
</div>""", unsafe_allow_html=True)
|
|
|
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 |
|
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)
|
|
|
|
|
|
|
|
|
|
|
|