import streamlit as st import joblib import numpy as np from huggingface_hub import hf_hub_download # Page configuration st.set_page_config( page_title="Loan Approval System", page_icon="🏦", layout="centered", initial_sidebar_state="collapsed" ) # Custom CSS for styling with the specified color theme st.markdown(""" """, unsafe_allow_html=True) # App header with banner image instead of title st.markdown('', unsafe_allow_html=True) # Load the trained model from Hugging Face @st.cache_resource def load_model(): model_path = hf_hub_download(repo_id="ifiecas/LoanApproval-DT-v1.0", filename="best_pruned_dt.pkl") return joblib.load(model_path) model = load_model() # Initialize session state for restart functionality if 'restart_clicked' not in st.session_state: st.session_state.restart_clicked = False # Create tabs for better organization tab1, tab2 = st.tabs(["Loan Application", "About the System"]) with tab1: # Reset all form values if restart was clicked if st.session_state.restart_clicked: st.session_state.restart_clicked = False # Reset flag # Personal Information Section st.markdown('

Personal Information

', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: gender = st.selectbox("Gender", ["Male", "Female"]) education = st.selectbox("Education Level", ["Graduate", "Under Graduate"]) with col2: marital_status = st.selectbox("Marital Status", ["Married", "Not Married"]) number_of_dependents = st.number_input("Number of Dependents", min_value=0, max_value=10, value=0) self_employed = st.selectbox("Self-Employed", ["No", "Yes"]) st.markdown('
', unsafe_allow_html=True) # Financial Details Section st.markdown('

Financial Details

', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: applicant_income = st.number_input("Monthly Income ($)", min_value=0, value=5000) loan_amount = st.number_input("Loan Amount ($)", min_value=0, value=100000) credit_history = st.selectbox("Credit History Status", [1, 0], format_func=lambda x: "No existing unsettled loans (1)" if x == 1 else "Have unsettled loans (0)") with col2: coapplicant_income = st.number_input("Co-Applicant's Income ($)", min_value=0) loan_term = st.slider("Loan Term (months)", min_value=12, max_value=360, value=180, step=12) location = st.selectbox("Property Location", ["Urban", "Semiurban", "Rural"]) st.markdown('
', unsafe_allow_html=True) # Summary section - without DTI Assessment or Eligibility Check st.markdown('

Application Summary

', unsafe_allow_html=True) total_income = applicant_income + coapplicant_income # Calculate monthly payment (simplified calculation) interest_rate = 0.05 # Assuming 5% annual interest rate monthly_interest = interest_rate / 12 num_payments = loan_term # Monthly payment using the loan amortization formula if monthly_interest == 0 or num_payments == 0: monthly_payment = 0 else: monthly_payment = loan_amount * (monthly_interest * (1 + monthly_interest) ** num_payments) / \ ((1 + monthly_interest) ** num_payments - 1) # Calculate DTI for backend use only (not displayed) dti = (monthly_payment / total_income) if total_income > 0 else 0 dti_percent = dti * 100 # Display summary metrics col1, col2, col3 = st.columns(3) col1.metric("Total Monthly Income", f"${total_income:,}") col2.metric("Estimated Monthly Payment", f"${monthly_payment:.2f}") col3.metric("Loan Term", f"{loan_term//12} years") # Add interest rate disclaimer st.markdown(f"""
* Estimated payment based on {interest_rate*100:.1f}% annual interest rate. Actual rates may vary.
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) # Prediction and restart buttons col1, col2 = st.columns([3, 1]) with col1: predict_button = st.button("Check Loan Approval Status", use_container_width=True) with col2: restart_button = st.button("🔄 Restart", use_container_width=True, help="Reset all form fields and start over") # Handle restart button click if restart_button: st.session_state.restart_clicked = True st.rerun() # Using st.rerun() instead of st.experimental_rerun() def preprocess_input(): # Convert categorical inputs to numerical format based on encoding reference gender_num = 0 if gender == "Male" else 1 marital_status_num = 0 if marital_status == "Not Married" else 1 education_num = 0 if education == "Under Graduate" else 1 self_employed_num = 0 if self_employed == "No" else 1 credit_history_num = credit_history # Already numerical (0,1) # One-Hot Encoding for Location location_semiurban = 1 if location == "Semiurban" else 0 location_urban = 1 if location == "Urban" else 0 # Convert Term from months to years term_years = loan_term / 12 # Compute Derived Features - use the same monthly payment calculated above debt_to_income = monthly_payment / total_income if total_income > 0 else 0 credit_amount_interaction = loan_amount * credit_history_num # Interaction effect income_term_ratio = total_income / term_years if term_years > 0 else 0 # Avoid divide by zero # Return array with all 16 features return np.array([[ gender_num, marital_status_num, number_of_dependents, education_num, self_employed_num, applicant_income, coapplicant_income, loan_amount, credit_history_num, total_income, debt_to_income, location_semiurban, location_urban, term_years, credit_amount_interaction, income_term_ratio ]]) # Display prediction if predict_button: with st.spinner("Processing your application..."): input_data = preprocess_input() prediction = model.predict(input_data) # Apply additional rules to override the model in certain cases (backend only) manual_rejection = False # Rule-based rejections that override the model (but don't show to user) if total_income < 1500: manual_rejection = True elif dti_percent > 50: manual_rejection = True elif credit_history == 0 and dti_percent > 35: manual_rejection = True # Final decision combines model prediction and manual eligibility checks final_approval = (prediction[0] == 1) and not manual_rejection # Show result with enhanced styling if final_approval: st.markdown("""

✅ Loan Approved

Congratulations! Based on your information, you're eligible for this loan.

""", unsafe_allow_html=True) else: st.markdown("""

❌ Loan Not Approved

Unfortunately, based on your current information, we cannot approve your loan application.

Consider improving your credit score, reducing existing debt, or applying with a co-applicant with higher income.

""", unsafe_allow_html=True) with tab2: # Add custom CSS for better styling st.markdown(""" """, unsafe_allow_html=True) # Main content container st.markdown('
', unsafe_allow_html=True) # System overview section st.markdown('
', unsafe_allow_html=True) st.markdown('

About the Loan Approval System

', unsafe_allow_html=True) st.markdown( '

This prototype evaluates loan applications using machine learning and ' 'industry-standard criteria. It analyzes financial information, credit history, and loan requirements' 'to provide fast, objective loan decisions.

', unsafe_allow_html=True ) st.markdown('
', unsafe_allow_html=True) # Model information section st.markdown('
', unsafe_allow_html=True) st.markdown('

About the ML Model

', unsafe_allow_html=True) st.markdown( '

The machine learning model powering this system is a Decision Tree classifier, ' 'which outperformed several alternatives including KNN, Random Forest, Logistic Regression, and Support ' 'Vector Machine in our testing phase. The model was refined using Cost Complexity Pruning (CCP) to identify ' 'the optimal alpha value, preventing overfitting while maintaining high predictive accuracy.

', unsafe_allow_html=True ) st.markdown('
', unsafe_allow_html=True) # Performance metrics section with cards st.markdown('
', unsafe_allow_html=True) st.markdown('

Model Performance Metrics

', unsafe_allow_html=True) # Metrics cards using HTML for better styling st.markdown( '
' '
' '
83.61%
' '
Accuracy
' '
' '
' '
80.77%
' '
Precision
' '
' '
' '
100.00%
' '
Recall
' '
' '
' '
89.36%
' '
F1 Score
' '
' '
', unsafe_allow_html=True ) # Link to documentation/more info st.markdown( '

For more information about the modeling process (from loading the dataset to fine-tuning ' 'the model), check here: Github

', unsafe_allow_html=True ) # YouTube video section st.markdown('

Brief Explanation

', unsafe_allow_html=True) st.markdown('

Watch this video for a brief explanation of the assessment:

', unsafe_allow_html=True) # YouTube embed with responsive container st.markdown("""
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) # Author section with profile st.markdown('
', unsafe_allow_html=True) st.markdown('

Behind the Build

', unsafe_allow_html=True) st.markdown( '
' '
IF
' '
' '

Ivy Fiecas-Borjal

' '

Building with AI & ML | Biz Dev in Tech

' '

' ' Visit Portfolio' '

' '
' '
', unsafe_allow_html=True ) st.markdown( '

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! 😊

', unsafe_allow_html=True ) st.markdown('
', unsafe_allow_html=True) # Disclaimer footer st.markdown("""""", unsafe_allow_html=True)