Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -146,9 +146,6 @@ with tab1:
|
|
146 |
# Reset all form values if restart was clicked
|
147 |
if st.session_state.restart_clicked:
|
148 |
st.session_state.restart_clicked = False # Reset flag
|
149 |
-
|
150 |
-
# Add any other reset logic here if needed
|
151 |
-
# Note: Streamlit will reset most inputs automatically on rerun
|
152 |
|
153 |
# Personal Information Section
|
154 |
st.markdown('<div class="section-card"><h3>Personal Information</h3>', unsafe_allow_html=True)
|
@@ -182,7 +179,7 @@ with tab1:
|
|
182 |
|
183 |
st.markdown('</div>', unsafe_allow_html=True)
|
184 |
|
185 |
-
# Summary section
|
186 |
st.markdown('<div class="section-card"><h3>Application Summary</h3>', unsafe_allow_html=True)
|
187 |
|
188 |
total_income = applicant_income + coapplicant_income
|
@@ -199,94 +196,23 @@ with tab1:
|
|
199 |
monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \
|
200 |
((1 + monthly_interest) ** num_payments - 1)
|
201 |
|
202 |
-
# Calculate
|
203 |
dti = (monthly_payment / total_income) if total_income > 0 else 0
|
204 |
dti_percent = dti * 100
|
205 |
|
|
|
206 |
col1, col2, col3 = st.columns(3)
|
207 |
col1.metric("Total Monthly Income", f"${total_income:,}")
|
208 |
col2.metric("Estimated Monthly Payment", f"${monthly_payment:.2f}")
|
209 |
col3.metric("Loan Term", f"{loan_term//12} years")
|
210 |
|
211 |
-
#
|
212 |
-
st.markdown("<h4>Debt-to-Income Assessment</h4>", unsafe_allow_html=True)
|
213 |
-
|
214 |
-
# Cap the displayed percentage at 100% for the visual
|
215 |
-
display_percent = min(dti_percent, 100)
|
216 |
-
|
217 |
-
# Determine the status and color
|
218 |
-
if dti_percent <= 36:
|
219 |
-
dti_status = "Good"
|
220 |
-
dti_color = "#4CAF50" # Green
|
221 |
-
emoji = "✅"
|
222 |
-
elif dti_percent <= 43:
|
223 |
-
dti_status = "Moderate"
|
224 |
-
dti_color = "#FF9800" # Orange
|
225 |
-
emoji = "⚠️"
|
226 |
-
else:
|
227 |
-
dti_status = "High"
|
228 |
-
dti_color = "#F44336" # Red
|
229 |
-
emoji = "❗"
|
230 |
-
|
231 |
-
# Create a visual progress bar
|
232 |
st.markdown(f"""
|
233 |
-
<div style="margin-
|
234 |
-
|
235 |
-
<div style="background-color: {dti_color}; width: {display_percent}%; height: 20px; border-radius: 10px;"></div>
|
236 |
-
</div>
|
237 |
-
<div style="display: flex; justify-content: space-between; font-size: 0.8rem;">
|
238 |
-
<span>0%</span>
|
239 |
-
<span>50%</span>
|
240 |
-
<span>100%+</span>
|
241 |
-
</div>
|
242 |
</div>
|
243 |
""", unsafe_allow_html=True)
|
244 |
|
245 |
-
# Show a simple explanation of DTI with actual values
|
246 |
-
if dti_percent > 100:
|
247 |
-
st.markdown(f"""
|
248 |
-
<div style="padding: 10px; background-color: #FFEBEE; border-radius: 5px; margin-bottom: 15px;">
|
249 |
-
{emoji} <strong>Your monthly payment (${monthly_payment:.2f}) would be {dti_percent/100:.1f}× your monthly income (${total_income:,})</strong>
|
250 |
-
<p style="margin: 5px 0 0 0; font-size: 0.9rem;">Most lenders require this to be below 43% for approval</p>
|
251 |
-
</div>
|
252 |
-
""", unsafe_allow_html=True)
|
253 |
-
else:
|
254 |
-
st.markdown(f"""
|
255 |
-
<div style="padding: 10px; background-color: #F5F5F5; border-radius: 5px; margin-bottom: 15px;">
|
256 |
-
{emoji} <strong>Your monthly payment (${monthly_payment:.2f}) would be {dti_percent:.1f}% of your monthly income (${total_income:,})</strong>
|
257 |
-
<p style="margin: 5px 0 0 0; font-size: 0.9rem;">Most lenders require this to be below 43% for approval</p>
|
258 |
-
</div>
|
259 |
-
""", unsafe_allow_html=True)
|
260 |
-
|
261 |
-
# Add eligibility check section
|
262 |
-
st.markdown('<h4>Loan Eligibility Check</h4>', unsafe_allow_html=True)
|
263 |
-
|
264 |
-
eligibility_issues = []
|
265 |
-
|
266 |
-
# Check minimum income threshold (example: $1500/month)
|
267 |
-
if total_income < 1500:
|
268 |
-
eligibility_issues.append("⚠️ Total monthly income below minimum requirement ($1,500)")
|
269 |
-
|
270 |
-
# Check if DTI is too high (above 43% is typically problematic)
|
271 |
-
if dti_percent > 43:
|
272 |
-
eligibility_issues.append("⚠️ Debt-to-income ratio exceeds maximum threshold (43%)")
|
273 |
-
|
274 |
-
# Credit history is critical
|
275 |
-
if credit_history == 0:
|
276 |
-
eligibility_issues.append("⚠️ Existing unsettled loans may affect approval odds")
|
277 |
-
|
278 |
-
# Display eligibility issues if any
|
279 |
-
if eligibility_issues:
|
280 |
-
st.markdown('<div style="background-color:#FFF3E0;padding:10px;border-radius:5px;margin-bottom:15px;">', unsafe_allow_html=True)
|
281 |
-
st.markdown("<p><strong>Potential eligibility concerns:</strong></p>", unsafe_allow_html=True)
|
282 |
-
for issue in eligibility_issues:
|
283 |
-
st.markdown(f"<p>{issue}</p>", unsafe_allow_html=True)
|
284 |
-
st.markdown("</div>", unsafe_allow_html=True)
|
285 |
-
else:
|
286 |
-
st.markdown('<div style="background-color:#E8F5E9;padding:10px;border-radius:5px;margin-bottom:15px;">', unsafe_allow_html=True)
|
287 |
-
st.markdown("<p>✅ <strong>No obvious eligibility concerns</strong></p>", unsafe_allow_html=True)
|
288 |
-
st.markdown("</div>", unsafe_allow_html=True)
|
289 |
-
|
290 |
st.markdown('</div>', unsafe_allow_html=True)
|
291 |
|
292 |
# Prediction and restart buttons
|
@@ -299,6 +225,11 @@ with tab1:
|
|
299 |
restart_button = st.button("🔄 Restart", use_container_width=True,
|
300 |
help="Reset all form fields and start over")
|
301 |
|
|
|
|
|
|
|
|
|
|
|
302 |
def preprocess_input():
|
303 |
# Convert categorical inputs to numerical format based on encoding reference
|
304 |
gender_num = 0 if gender == "Male" else 1
|
@@ -327,31 +258,22 @@ with tab1:
|
|
327 |
credit_amount_interaction, income_term_ratio
|
328 |
]])
|
329 |
|
330 |
-
# Handle restart button click
|
331 |
-
if restart_button:
|
332 |
-
st.session_state.restart_clicked = True
|
333 |
-
st.rerun() # Using st.rerun() instead of st.experimental_rerun()
|
334 |
-
|
335 |
# Display prediction
|
336 |
if predict_button:
|
337 |
with st.spinner("Processing your application..."):
|
338 |
input_data = preprocess_input()
|
339 |
prediction = model.predict(input_data)
|
340 |
|
341 |
-
# Apply additional rules to override the model in certain cases
|
342 |
manual_rejection = False
|
343 |
-
rejection_reason = ""
|
344 |
|
345 |
# Rule-based rejections that override the model (but don't show to user)
|
346 |
if total_income < 1500:
|
347 |
manual_rejection = True
|
348 |
-
rejection_reason = "Insufficient income"
|
349 |
elif dti_percent > 50:
|
350 |
manual_rejection = True
|
351 |
-
rejection_reason = "Payment too high relative to income"
|
352 |
elif credit_history == 0 and dti_percent > 35:
|
353 |
-
manual_rejection = True
|
354 |
-
rejection_reason = "Credit history and payment factors"
|
355 |
|
356 |
# Final decision combines model prediction and manual eligibility checks
|
357 |
final_approval = (prediction[0] == 1) and not manual_rejection
|
@@ -365,7 +287,7 @@ with tab1:
|
|
365 |
</div>
|
366 |
""", unsafe_allow_html=True)
|
367 |
else:
|
368 |
-
st.markdown(
|
369 |
<div class="result-rejected">
|
370 |
<h3 style="color: #C62828;">❌ Loan Not Approved</h3>
|
371 |
<p>Unfortunately, based on your current information, we cannot approve your loan application.</p>
|
@@ -388,33 +310,19 @@ with tab2:
|
|
388 |
- Credit history status
|
389 |
- Loan amount and term
|
390 |
- Income and employment status
|
391 |
-
- Debt-to-income ratio
|
392 |
""")
|
393 |
|
394 |
st.write("""
|
395 |
Our decision engine combines a trained machine learning model with industry-standard lending criteria.
|
396 |
-
The system evaluates your application against patterns from thousands of previous loan applications
|
397 |
-
while also applying standard financial rules used by major lenders.
|
398 |
""")
|
399 |
|
400 |
-
st.markdown('<div class="section-card">', unsafe_allow_html=True)
|
401 |
-
st.markdown("<h3>Important Factors for Approval</h3>", unsafe_allow_html=True)
|
402 |
-
st.write("To maximize your chances of approval:")
|
403 |
-
st.markdown("""
|
404 |
-
- Maintain a debt-to-income ratio below 43%
|
405 |
-
- Have sufficient monthly income (minimum $1,500)
|
406 |
-
- Clear existing unsettled loans when possible
|
407 |
-
- Consider adding a co-applicant to strengthen your application
|
408 |
-
""")
|
409 |
-
st.markdown('</div>', unsafe_allow_html=True)
|
410 |
-
|
411 |
st.markdown('<div class="section-card">', unsafe_allow_html=True)
|
412 |
st.markdown("<h3>Key Features</h3>", unsafe_allow_html=True)
|
413 |
st.write("Our system provides:")
|
414 |
st.markdown("""
|
415 |
- Instant loan approval decisions
|
416 |
- Transparent evaluation process
|
417 |
-
- Detailed eligibility assessment
|
418 |
- Secure data handling
|
419 |
""")
|
420 |
st.markdown('</div>', unsafe_allow_html=True)
|
|
|
146 |
# Reset all form values if restart was clicked
|
147 |
if st.session_state.restart_clicked:
|
148 |
st.session_state.restart_clicked = False # Reset flag
|
|
|
|
|
|
|
149 |
|
150 |
# Personal Information Section
|
151 |
st.markdown('<div class="section-card"><h3>Personal Information</h3>', unsafe_allow_html=True)
|
|
|
179 |
|
180 |
st.markdown('</div>', unsafe_allow_html=True)
|
181 |
|
182 |
+
# Summary section - without DTI Assessment or Eligibility Check
|
183 |
st.markdown('<div class="section-card"><h3>Application Summary</h3>', unsafe_allow_html=True)
|
184 |
|
185 |
total_income = applicant_income + coapplicant_income
|
|
|
196 |
monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \
|
197 |
((1 + monthly_interest) ** num_payments - 1)
|
198 |
|
199 |
+
# Calculate DTI for backend use only (not displayed)
|
200 |
dti = (monthly_payment / total_income) if total_income > 0 else 0
|
201 |
dti_percent = dti * 100
|
202 |
|
203 |
+
# Display summary metrics
|
204 |
col1, col2, col3 = st.columns(3)
|
205 |
col1.metric("Total Monthly Income", f"${total_income:,}")
|
206 |
col2.metric("Estimated Monthly Payment", f"${monthly_payment:.2f}")
|
207 |
col3.metric("Loan Term", f"{loan_term//12} years")
|
208 |
|
209 |
+
# Add interest rate disclaimer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
st.markdown(f"""
|
211 |
+
<div style="font-size: 0.8rem; color: #666; margin-top: -10px; margin-bottom: 20px;">
|
212 |
+
* Estimated payment based on {interest_rate*100:.1f}% annual interest rate. Actual rates may vary.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
</div>
|
214 |
""", unsafe_allow_html=True)
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
st.markdown('</div>', unsafe_allow_html=True)
|
217 |
|
218 |
# Prediction and restart buttons
|
|
|
225 |
restart_button = st.button("🔄 Restart", use_container_width=True,
|
226 |
help="Reset all form fields and start over")
|
227 |
|
228 |
+
# Handle restart button click
|
229 |
+
if restart_button:
|
230 |
+
st.session_state.restart_clicked = True
|
231 |
+
st.rerun() # Using st.rerun() instead of st.experimental_rerun()
|
232 |
+
|
233 |
def preprocess_input():
|
234 |
# Convert categorical inputs to numerical format based on encoding reference
|
235 |
gender_num = 0 if gender == "Male" else 1
|
|
|
258 |
credit_amount_interaction, income_term_ratio
|
259 |
]])
|
260 |
|
|
|
|
|
|
|
|
|
|
|
261 |
# Display prediction
|
262 |
if predict_button:
|
263 |
with st.spinner("Processing your application..."):
|
264 |
input_data = preprocess_input()
|
265 |
prediction = model.predict(input_data)
|
266 |
|
267 |
+
# Apply additional rules to override the model in certain cases (backend only)
|
268 |
manual_rejection = False
|
|
|
269 |
|
270 |
# Rule-based rejections that override the model (but don't show to user)
|
271 |
if total_income < 1500:
|
272 |
manual_rejection = True
|
|
|
273 |
elif dti_percent > 50:
|
274 |
manual_rejection = True
|
|
|
275 |
elif credit_history == 0 and dti_percent > 35:
|
276 |
+
manual_rejection = True
|
|
|
277 |
|
278 |
# Final decision combines model prediction and manual eligibility checks
|
279 |
final_approval = (prediction[0] == 1) and not manual_rejection
|
|
|
287 |
</div>
|
288 |
""", unsafe_allow_html=True)
|
289 |
else:
|
290 |
+
st.markdown("""
|
291 |
<div class="result-rejected">
|
292 |
<h3 style="color: #C62828;">❌ Loan Not Approved</h3>
|
293 |
<p>Unfortunately, based on your current information, we cannot approve your loan application.</p>
|
|
|
310 |
- Credit history status
|
311 |
- Loan amount and term
|
312 |
- Income and employment status
|
|
|
313 |
""")
|
314 |
|
315 |
st.write("""
|
316 |
Our decision engine combines a trained machine learning model with industry-standard lending criteria.
|
317 |
+
The system evaluates your application against patterns from thousands of previous loan applications.
|
|
|
318 |
""")
|
319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
st.markdown('<div class="section-card">', unsafe_allow_html=True)
|
321 |
st.markdown("<h3>Key Features</h3>", unsafe_allow_html=True)
|
322 |
st.write("Our system provides:")
|
323 |
st.markdown("""
|
324 |
- Instant loan approval decisions
|
325 |
- Transparent evaluation process
|
|
|
326 |
- Secure data handling
|
327 |
""")
|
328 |
st.markdown('</div>', unsafe_allow_html=True)
|