ml_cloud_sn / app.py
danielle2003's picture
Update app.py
d5122ba verified
import streamlit as st
import pandas as pd
import joblib
import numpy as np
import warnings
from streamlit.components.v1 import html
import time # For simulating loading
# --- Set page configuration ---
st.set_page_config(
page_title="CreditIQ - AI-Powered Credit Expenditure Prediction",
page_icon="💳",
layout="wide", # Use wide layout to better accommodate complex design
initial_sidebar_state="collapsed" # Hide sidebar to give full canvas
)
# --- Initialize session state for page management ---
if 'active_page' not in st.session_state:
st.session_state.active_page = 'home'
if 'show_prediction' not in st.session_state:
st.session_state.show_prediction = False
if 'predicted_value' not in st.session_state:
st.session_state.predicted_value = 0.0
warnings.filterwarnings('ignore')
st.markdown("""
<style>
/* Hide Streamlit's default header, footer, and hamburger menu */
#MainMenu, header, footer { visibility: hidden; }
/* Remove padding from the main block container for a full-width feel */
.block-container {
padding: 0 !important;
}
[class*="st-key-dismiss_modal_btn"] {
display:none;
}
div.stButton > button {
background: transparent;
color: var(--gray-light);
text-decoration: none !important;
font-weight: 500;
transition: all 0.3s ease;
font-family: "Times New Roman " !important; /* Font */
font-size: 18px !important; /* Font size */
border: none; /* Remove border */
display: flex;
align-items: center;
justify-content: center;
width:110px;
height:50px;
margin-top:-5px;
position:fixed;
z-index:10000000;
}
div[data-testid="stSelectbox"]
{{
background-color: white !important;
position: relative;
border-bottom:1px solid #ccc;
border-radius:0px;
}}
div[data-testid="stTextInput"]{{
}}
div[data-testid="stTextInput"] > div >div {{
background-color: rgba(255, 158, 87, 0.12) !important;
}}
div[data-testid="stTextInputRootElement"]{{
border: 1px solid white !important;
}}
/* Hover effect */
div.stButton > button:hover {
color: var(--white) !important;
transform: none !important;
}
div.stButton > button.active {
color: var(--white) !important;
}
/* Style the sidebar to have a modern, dark look */
section[data-testid="stSidebar"] {{
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.15);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.01);
height:100px;
[data-testid="stSidebar"] h2 {{
color: #FFFFFF; /* White headers in the sidebar */
font-family:time new roman !important;
}}
[data-testid="stSidebar"] .st-emotion-cache-1629p8f a {{
color: #94A3B8; /* Lighter text color for links */
font-family:time new roman !important;
}}
[data-testid="stImageContainer"]>img{{
max-width:70% !important;
margin-top:-70px;
}}
div[data-testid="stMarkdownContainer"] >p{{
font-family:time new roman !important;
}}
</style>
""", unsafe_allow_html=True)
# --- Inject Custom HTML, CSS, and Inline JavaScript ---
# This block defines the sophisticated styling and background animations,
# navigation, and overall page structure.
# Streamlit components will be injected into specific HTML placeholders.
st.markdown(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CreditIQ - AI-Powered Credit Expenditure Prediction</title>
<meta name="description" content="Professional AI-powered credit card expenditure prediction platform. Get accurate spending forecasts with advanced machine learning algorithms.">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>💳</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
/* General Resets */
* {{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family:time new roman !important;
}}
html, body, .main {{
margin: 0;
padding: 0;
height: 100%;
overflow-x: hidden;
position: relative;
}}
i[class^="fa"], i[class*=" fa"] {{
font-family: "Font Awesome 6 Free" !important;
font-weight: 900 !important;
font-style: normal !important;
display: inline-block !important;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
}}
/* Custom Button Styling for Navigation */
.nav-button {{
background: transparent !important;
color: var(--gray-light) !important;
border: none !important;
font-weight: 500 !important;
font-family: 'Inter', sans-serif !important;
padding: 0 !important;
text-align: center;
position: relative;
transition: all 0.3s ease;
box-shadow: none !important;
}}
[class*="st-key-nav_"]:hover {{
color: var(--white) !important;
transform: none !important;
}}
[class*="st-key-nav_home_home"]::after
{{
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 100%;
height: 2px;
background: var(--gradient-accent);
color: var(--white) !important;
margin-left:15px;
}}
[class*="st-key-nav_about_about"]::after
{{
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 100%;
height: 2px;
background: var(--gradient-accent);
color: var(--white) !important;
margin-left:15px;
}}
[class*="st-key-nav_predictor_predictor"]::after
{{
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 100%;
height: 2px;
background: var(--gradient-accent);
color: var(--white) !important;
margin-left:15px;
}}
[class*="st-key-nav_features_features"]::after
{{
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 100%;
height: 2px;
background: var(--gradient-accent);
color: var(--white) !important;
margin-left:15px;
}}
[class*="st-key-nav_contact_contact"]::after
{{
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 45%;
height: 2px;
background: var(--gradient-accent);
color: var(--white) !important;
margin-left:15px;
}}
/* Root Variables for Colors and Shadows */
:root {{
--primary: #4F46E5;
--primary-dark: #3730A3;
--secondary: #06B6D4;
--accent: #8B5CF6;
--success: #10B981;
--warning: #F59E0B;
--error: #EF4444;
--dark: #0F172A;
--dark-light: #1E293B;
--gray: #64748B;
--gray-light: #94A3B8;
--white: #FFFFFF;
--glass-bg: rgba(255, 255, 255, 0.1);
--glass-nav: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.2);
--gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-secondary: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--gradient-accent: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.1);
--shadow-md: 0 8px 32px rgba(0, 0, 0, 0.15);
--shadow-lg: 0 16px 64px rgba(0, 0, 0, 0.2);
}}
/* Body and App Background */
body, .stApp {{
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #0F172A 0%, #1E293B 100%);
color: var(--white);
line-height: 1.6;
overflow-x: hidden;
height: 100vh;
position: relative; /* Needed for absolute positioning of bg-animation */
}}
/* Streamlit's main content wrapper */
.st-emotion-block-container {{
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
position: relative;
z-index: 1; /* Ensure content is above backgrounds */
}}
/* Background Animation */
.bg-animation {{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2; /* Ensure it's behind everything */
background: linear-gradient(45deg, #667eea, #764ba2, #f093fb, #f5576c, #4facfe, #00f2fe);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
}}
@keyframes gradientShift {{
0% {{ background-position: 0% 50%; }}
50% {{ background-position: 100% 50%; }}
100% {{ background-position: 0% 50%; }}
}}
/* Floating Shapes Animation */
.floating-shapes {{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1; /* Above bg-animation, below content */
pointer-events: none; /* Allows clicks to pass through */
}}
.shape {{
position: absolute;
opacity: 0.1;
animation: float 20s infinite ease-in-out;
}}
.shape:nth-child(1) {{
top: 10%;
left: 10%;
width: 80px;
height: 80px;
background: var(--gradient-accent);
border-radius: 50%;
animation-delay: 0s;
}}
.shape:nth-child(2) {{
top: 70%;
right: 10%;
width: 120px;
height: 120px;
background: var(--gradient-secondary);
border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
animation-delay: 5s;
}}
.shape:nth-child(3) {{
bottom: 20%;
left: 20%;
width: 100px;
height: 100px;
background: var(--gradient-primary);
border-radius: 20px;
transform: rotate(45deg);
animation-delay: 10s;
}}
@keyframes float {{
0%, 100% {{ transform: translateY(0px) rotate(0deg); }}
33% {{ transform: translateY(-30px) rotate(120deg); }}
66% {{ transform: translateY(15px) rotate(240deg); }}
}}
/* Navigation */
.navbar {{
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
transition: all 0.3s ease;
background: var(--glass-nav);
backdrop-filter: blur(20px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}}
.navbar.scrolled {{
background: rgba(15, 23, 42, 0.98);
box-shadow: var(--shadow-md);
}}
.nav-container {{
max-width: 1500px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
height: 80px;
}}
.logo {{
font-size: 1.8rem;
font-weight: 800;
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-decoration: none;
}}
.nav-menu {{
display: flex;
list-style: none;
gap: 2rem;
align-items: center;
}}
.nav-link {{
color: var(--gray-light);
text-decoration: none !important;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
}}
.nav-link:hover,
.nav-link.active {{
color: var(--white);
}}
.nav-link::after {{
content: '';
position: absolute;
bottom: -5px;
left: 0;
width: 0;
height: 2px;
background: var(--gradient-accent);
transition: width 0.3s ease;
}}
.nav-link:hover::after,
.nav-link.active::after {{
width: 100%;
}}
.cta-btn {{
background: var(--gradient-accent);
color: var(--white);
padding: 0.75rem 1.5rem;
border-radius: 50px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: var(--shadow-sm);
}}
.cta-btn:hover {{
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}}
.mobile-menu-btn {{
display: none;
background: none;
border: none;
color: var(--white);
font-size: 1.5rem;
cursor: pointer;
}}
/* Hero Section */
.hero {{
height: 900px;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
padding-top: 80px; /* Account for fixed navbar */
margin-top:-250px;
}}
.hero-bg {{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--gradient-primary);
opacity: 0.1;
/*animation: gradientShift 15s ease infinite;*/
z-index: -1;
}}
.hero-container {{
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: center;
position: relative;
z-index: 1;
width: 100%; /* Ensure it takes full width of st.container */
}}
.hero-content h1 {{
font-size: 4rem;
font-weight: 900;
line-height: 1.1;
margin-bottom: 1.5rem;
background: linear-gradient(135deg, #fff, #e2e8f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}}
.hero-content .highlight {{
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}}
.hero-content p {{
font-size: 1.2rem;
color: var(--gray-light);
margin-bottom: 2rem;
max-width: 500px;
}}
.hero-buttons {{
display: flex;
gap: 1rem;
flex-wrap: wrap;
}}
.btn-primary {{
background: var(--gradient-accent);
color: var(--white);
padding: 1rem 2rem;
border-radius: 50px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
box-shadow: var(--shadow-md);
}}
.btn-primary:hover {{
transform: translateY(-3px);
box-shadow: var(--shadow-lg);
}}
.btn-secondary {{
background: transparent;
color: var(--white);
padding: 1rem 2rem;
border: 2px solid var(--glass-border);
border-radius: 50px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}}
.btn-secondary:hover {{
background: var(--glass-bg);
border-color: var(--white);
}}
.hero-visual {{
position: relative;
height: 500px; /* Fixed height for visual consistency */
width: 100%;
}}
.hero-card {{
position: absolute;
background: var(--glass-bg);
backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 2rem;
box-shadow: var(--shadow-lg);
animation: float 6s ease-in-out infinite;
}}
.hero-card:nth-child(1) {{
top: 0;
left: 0;
width: 280px;
animation-delay: 0s;
}}
.hero-card:nth-child(2) {{
top: 100px;
right: 0;
width: 250px;
animation-delay: 2s;
}}
.hero-card:nth-child(3) {{
bottom: 0;
left: 50px;
width: 200px;
animation-delay: 4s;
}}
/* Main Content Pages */
/* Streamlit will show/hide these based on st.session_state */
.page {{
display: none; /* Controlled by Streamlit's Python logic */
height: 900px;
padding: 120px 0 80px; /* Padding for header/footer */
margin-top: -250px;
}}
.page.active {{
display: block; /* Shown by Streamlit */
margin-top: -100px !important;
}}
.page-header {{
text-align: center;
margin-bottom: 4rem;
margin-top:-50px;
}}
.page-header h1 {{
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #fff, #e2e8f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}}
.page-header p {{
font-size: 1.2rem;
color: var(--gray-light);
max-width: 600px;
margin: 0 auto;
margin-top:-20px
}}
/* Predictor Form */
/* Streamlit Help Text Overrides */
.st-cg, .st-cr {{
font-size: 0.8rem;
color: var(--gray-light);
margin-top: 0.25rem;
}}
.predict-btn-custom {{ /* Custom class to be used by st.button */
background: var(--gradient-accent) !important;
color: var(--white) !important;
padding: 1.25rem 3rem !important;
border: none !important;
border-radius: 50px !important;
font-size: 1.1rem !important;
font-weight: 700 !important;
cursor: pointer !important;
transition: all 0.3s ease !important;
display: block !important;
margin: 2rem auto !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
box-shadow: var(--shadow-md) !important;
position: relative !important;
overflow: hidden !important;
}}
.predict-btn-custom:hover {{
transform: translateY(-3px) !important;
box-shadow: var(--shadow-lg) !important;
}}
.predict-btn-custom::before {{
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}}
.predict-btn-custom:hover::before {{
left: 100%;
}}
.result-card {{
background: var(--glass-bg);
backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 3rem;
text-align: center;
transform: translateY(30px);
transition: all 0.5s ease;
}}
.result-card.show {{
opacity: 1;
transform: translateY(0);
}}
.result-amount {{
font-size: 3.5rem;
font-weight: 900;
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 1rem;
animation: countUp 1s ease-out;
}}
/* Features Section */
.features-grid {{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin:25px;
}}
.feature-card {{
background: var(--glass-bg);
backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 2.5rem;
text-align: center;
transition: all 0.3s ease;
box-shadow: var(--shadow-sm); /* Default shadow */
}}
.feature-card:hover {{
transform: translateY(-10px);
box-shadow: var(--shadow-lg);
}}
.feature-icon {{
font-size: 3rem;
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 1rem;
}}
.feature-card h3 {{
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1rem;
color: var(--white); /* Ensure headings are visible */
}}
/* About Section */
.about-content {{
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: center;
margin:30px;
}}
.about-text h2 {{
font-size: 2.5rem;
font-weight: 800;
margin-bottom: 1.5rem;
background: linear-gradient(135deg, #fff, #e2e8f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}}
.about-text p {{
margin-bottom: 1.5rem;
color: var(--gray-light);
font-size: 1.1rem;
}}
.stats-grid {{
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2rem;
margin-top: 3rem;
}}
.stat-card {{
text-align: center;
padding: 2rem;
background: var(--glass-bg);
border-radius: 16px;
box-shadow: var(--shadow-sm);
}}
.stat-number {{
font-size: 2.5rem;
font-weight: 900;
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}}
/* Contact Section */
[class*="st-key-contact-form"]{{
background: var(--glass-bg);
backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 0.5rem;
max-width: 800px;
margin: 0 auto;
margin-top:-680px;
max-height:400px !important;
}}
/* Loading Animation */
.loading {{
display: none; /* Controlled by Streamlit's session state */
text-align: center;
padding: 2rem;
}}
.loading.show {{
display: block;
}}
.spinner {{
width: 40px;
height: 40px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-top: 3px solid var(--secondary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}}
@keyframes spin {{
0% {{ transform: rotate(0deg); }}
100% {{ transform: rotate(360deg); }}
}}
/* Responsive Design */
@media (max-width: 768px) {{
.mobile-menu-btn {{
display: block;
}}
.nav-menu {{
position: fixed;
top: 80px;
left: -100%;
width: 100%;
height: calc(100vh - 80px);
background: var(--dark);
flex-direction: column;
justify-content: center;
transition: left 0.3s ease;
}}
.nav-menu.active {{
left: 0;
}}
.hero-container {{
grid-template-columns: 1fr;
text-align: center;
padding-top: 2rem; /* Adjust padding for mobile hero */
}}
.hero-visual {{
height: auto; /* Allow height to adjust */
margin-top: 2rem;
}}
.hero-card {{
position: static; /* Remove absolute positioning on mobile */
width: 100%;
margin-bottom: 1.5rem;
animation: none; /* Disable float animation on mobile */
}}
.page {{
padding: 100px 0 60px; /* Adjust page padding for mobile */
}}
.header h1, .page-header h1 {{
font-size: 2.5rem;
}}
.header .icon {{
font-size: 3rem;
}}
.main-form, .predictor-form, .contact-form {{
padding: 2rem;
border-radius: 24px;
}}
.input-grid, .form-grid {{
grid-template-columns: 1fr;
gap: 1.5rem;
}}
.result-amount {{
font-size: 2.5rem;
}}
.about-content, .footer-content {{
grid-template-columns: 1fr;
}}
.stats-grid {{
grid-template-columns: 1fr;
}}
}}
/* Streamlit Specific Overrides */
/* Hide Streamlit's default header/footer elements */
footer {{ visibility: hidden; height: 0; overflow: hidden; }} /* Hides Streamlit's "Made with Streamlit" */
#MainMenu {{ visibility: hidden; }} /* Hides Streamlit's main menu icon */
.css-vk325g {{ /* Targets the header elements generated by Streamlit */
display: none !important;
}}
</style>
</head>
<body>
<div class="bg-animation"></div>
<div class="floating-shapes">
<div class="shape"></div>
<div class="shape"></div>
<div class="shape"></div>
</div>
<!-- Navigation -->
<nav class="navbar" id="navbar">
<div class="nav-container">
<a href="#" class="logo" onclick="showPage('home')">CreditIQ</a>
""",unsafe_allow_html=True)
nav_cols = st.columns([5, 0.5, 0.5, 0.5, 0.5, 1])
with nav_cols[0]:
st.markdown('<p class="logo">CreditIQ</p>', unsafe_allow_html=True)
nav_items = ["home", "predictor", "features", "about", "contact"]
for i, item in enumerate(nav_items):
with nav_cols[i+1]:
active = "active" if st.session_state.active_page == item else ""
# Each button click updates the session state and triggers a rerun
if st.button(item, key=f"nav_{item}_{st.session_state.active_page}", use_container_width=True):
st.session_state.active_page = item
st.session_state.show_prediction = False # Reset prediction display
st.rerun()
# JavaScript to apply the correct CSS classes to the Streamlit buttons
st.markdown("""
<script>
const buttons = window.parent.document.querySelectorAll('.stButton button');
const activePage = '""" + st.session_state.active_page + """';
buttons.forEach(button => {
const buttonText = button.innerText;
if (["Home", "Predictor", "Features", "About", "Contact"].includes(buttonText)) {
button.classList.add('nav-button');
if (buttonText === activePage) {
button.classList.add('active');
}
}
});
</script>
""", unsafe_allow_html=True)
st.markdown(f"""
</div>
</nav>
<!-- Content Pages (managed by Streamlit Python logic) -->
<div id="streamlit_content_container">
<!-- Streamlit will inject its components here, corresponding to active_page -->
</div>
<!-- This part of the HTML is only for the footer, as Streamlit manages the main content -->
<footer class="app-footer">
<div class="footer-content">
<div class="footer-section">
<h3>CreditIQ</h3>
<p style="color: var(--gray-light); font-size: 0.9rem;">Your trusted AI partner for credit expenditure forecasting. Empowering financial decisions.</p>
</div>
<div class="footer-section">
<h3>Quick Links</h3>
<ul>
<li><a href="#" onclick="showPage('home')">Home</a></li>
<li><a href="#" onclick="showPage('predictor')">Predictor</a></li>
<li><a href="#" onclick="showPage('features')">Features</a></li>
<li><a href="#" onclick="showPage('about')">About</a></li>
</ul>
</div>
<div class="footer-section">
<h3>Contact Us</h3>
<p style="color: var(--gray-light);"><i class="fas fa-envelope"></i> [email protected]</p>
<p style="color: var(--gray-light);"><i class="fas fa-phone"></i> +1 (123) 456-7890</p>
</div>
<div class="footer-section">
<h3>Follow Us</h3>
<ul style="display: flex; gap: 1rem;">
<li><a href="#" style="font-size: 1.2rem;"><i class="fab fa-facebook-f"></i></a></li>
<li><a href="#" style="font-size: 1.2rem;"><i class="fab fa-twitter"></i></a></li>
<li><a href="#" style="font-size: 1.2rem;"><i class="fab fa-linkedin-in"></i></a></li>
<li><a href="#" style="font-size: 1.2rem;"><i class="fab fa-instagram"></i></a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
&copy; 2023 CreditIQ. All rights reserved.
</div>
</footer>
</body>
</html>
""", unsafe_allow_html=True)
st.markdown("""
<style>
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--accent-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
--dark-gradient: linear-gradient(135deg, #0c0c0c 0%, #1a1a1a 100%);
--glass-bg: rgba(255, 255, 255, 0.1);
--glass-border: rgba(255, 255, 255, 0.2);
--shadow-medium: 0 16px 64px rgba(0, 0, 0, 0.15);
--shadow-strong: 0 24px 96px rgba(0, 0, 0, 0.2);
}
.bg-animation {
position: fixed; top: 0; left: 0;
width: 100%; height: 100%; z-index: -2;
background: linear-gradient(45deg, #667eea, #764ba2, #f093fb, #f5576c, #4facfe, #00f2fe);
background-size: 400% 400%; animation: gradientShift 15s ease infinite;
}
@keyframes gradientShift { 0% {background-position: 0% 50%;} 50% {background-position: 100% 50%;} 100% {background-position: 0% 50%;} }
.floating-shapes {
position: fixed; top: 0; left: 0;
width: 100%; height: 100%; z-index: -1; pointer-events: none;
}
.shape { position: absolute; opacity: 0.1; animation: float 20s infinite ease-in-out; }
.shape:nth-child(1) { top: 10%; left: 10%; width: 80px; height: 80px; background: var(--accent-gradient); border-radius: 50%; }
.shape:nth-child(2) { top: 70%; right: 10%; width: 120px; height: 120px; background: var(--secondary-gradient); border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; animation-delay: 5s; }
.shape:nth-child(3) { bottom: 20%; left: 20%; width: 100px; height: 100px; background: var(--primary-gradient); border-radius: 20px; transform: rotate(45deg); animation-delay: 10s; }
@keyframes float { 0%, 100% {transform: translateY(0px) rotate(0deg);} 33% {transform: translateY(-30px) rotate(120deg);} 66% {transform: translateY(15px) rotate(240deg);} }
/* Header and Form Styling */
.header { text-align: center; margin-bottom: 3rem; }
.header h1 { font-size: 3.5rem; font-weight: 900; background: linear-gradient(135deg, #fff, #f0f0f0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem; }
.header .icon { font-size: 4rem; margin-bottom: 1rem; background: var(--accent-gradient); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.header p { font-size: 1.2rem; color: rgba(255, 255, 255, 0.8); max-width: 600px; margin: 0 auto; }
.section-title {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 2rem;
text-align: center;
background: linear-gradient(135deg, #fff, #f0f0f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-family:time new roman !important;
}
/* Styling Streamlit Widgets to Match Your Design */
.stTextInput label, .stNumberInput label, .stSelectbox label {
font-weight: 500; margin-bottom: 0.5rem; color: rgba(255, 255, 255, 0.9);
font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;
font-family:time new roman !important;
}
.stTextInput label > div > p, .stNumberInput label > div > p , .stSelectbox label > div > p {
font-family:time new roman !important;
}
.stTextInput input, .stNumberInput input{
width: 100%; padding: 1rem 1.25rem;
background: rgba(255, 255, 255, 0.1) !important;
border: 1px solid rgba(255, 255, 255, 0.2) !important;
border-radius: 16px !important; color: #004cff !important;
font-size: 1rem !important; transition: all 0.3s ease !important;
backdrop-filter: blur(10px) !important;
font-family:time new roman !important;
}
.stSelectbox div[data-baseweb="select"] > div {
font-family:time new roman !important;
}
.stForm [data-testid="stFormSubmitButton"] button > div > p {
font-family:time new roman !important;
}
.stForm [data-testid="stFormSubmitButton"] button {
background: var(--accent-gradient); border: none; padding: 1.25rem 3rem;
border-radius: 50px; color: white; font-size: 1.1rem;
font-weight: 700; cursor: pointer; transition: all 0.3s ease;
text-transform: uppercase; letter-spacing: 1px;
box-shadow: var(--shadow-medium); display: block; margin: 2rem auto;
font-family:time new roman !important;
height:60px;
text-align:center;
margin-top:-3px;
}
.stForm [data-testid="stFormSubmitButton"] button:hover {
transform: translateY(-3px); box-shadow: var(--shadow-strong);
font-family:time new roman !important;
}
[class*="st-key-pred"] >div >button >div >p {
text-decoration: underline;
color:var(--primary);
width:200px;
font-weight:bold;
}
[class*="st-key-pred"]>div >button:active {
background:transparent !important;
}
[class*="st-key-abt"] >div >button >div >p {
text-decoration: underline;
color:var(--primary);
width:200px;
font-weight:bold;
}
[class*="st-key-abt"]>div >button:active {
background:transparent !important;
}
[class*="st-key-navbtn"] {
display: flex;
gap: 1rem;
z-index:100000000;
margin-top:-330px;
flex-wrap: wrap;
margin-left:200px;
}
[class*="st-key-abt"] {
background: transparent;
color: var(--white);
padding: 1rem 2rem;
border: 2px solid var(--glass-border);
border-radius: 50px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
width:185px;
margin-left:220px;
height:60px;
margin-top:-74px;
}
[class*="st-key-pred"] {
background: var(--gradient-accent);
color: var(--white);
padding: 1rem 2rem;
border-radius: 50px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
box-shadow: var(--shadow-md);
width:200px;
height:60px;
}
[class*="st-key-pred"] :hover {
transform: translateY(-3px); box-shadow: var(--shadow-strong);
font-family:time new roman !important;
}
/* Result Card */
.result-card {
background: var(--glass-bg); backdrop-filter: blur(20px);
border: 1px solid var(--glass-border); border-radius: 24px;
padding: 2.5rem; margin-top: 2rem; text-align: center;
box-shadow: var(--shadow-medium);
}
.result-amount { font-size: 3rem; font-weight: 900; background: var(--accent-gradient); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem; }
.result-label { font-size: 1.2rem; color: rgba(255, 255, 255, 0.8); margin-bottom: 1rem; }
button[kind="secondary"] {
position: relative !important;
}
button[kind="secondary"]:hover,button[kind="secondary"]:active {
color: var(--white) !important;
}
button[kind="secondary"]:active {
background: linear-gradient(to right, #4f46e5, #9333ea);
}
[class*="st-key-main-form"]{
background: var(--glass-bg); backdrop-filter: blur(20px);
border: 1px solid var(--glass-border); border-radius: 32px;
padding: 3rem; box-shadow: var(--shadow-strong);
width:60%;
align-self: center;
color:blue;
max-height:520px;
}
</style>
""", unsafe_allow_html=True)
# --- Load the trained model ---
@st.cache_resource
def load_model():
try:
model = joblib.load('credit_card_expenditure_model.joblib')
return model
except FileNotFoundError:
st.error("Model file 'credit_card_expenditure_model.joblib' not found. Please ensure it's in the same directory as this app.")
st.stop() # Stop the app if model is not found
except Exception as e:
st.error(f"Error loading model: {e}")
st.stop()
# --- Streamlit Content Injection ---
# This section uses st.empty() to create a placeholder where our content
# for the active page will be rendered.
streamlit_content_placeholder = st.empty()
# --- Page Rendering Logic based on active_page state ---
with streamlit_content_placeholder.container():
# Home Page
if st.session_state.active_page == 'home':
st.markdown(f"""
<div id="home" class="page active">
<section class="hero">
<div class="hero-bg"></div>
<div class="hero-container">
<div class="hero-content">
<h1>Predict Credit <span class="highlight">Expenditure</span> with AI</h1>
<p>Harness the power of advanced machine learning to accurately forecast credit card spending patterns and make informed financial decisions.</p>
</div>
<div class="hero-visual">
<div class="hero-card">
<i class="fas fa-brain" style="font-size: 2rem; color: #4facfe; margin-bottom: 1rem;"></i>
<h3>AI-Powered</h3>
<p>Advanced algorithms analyze spending patterns</p>
</div>
<div class="hero-card">
<i class="fas fa-shield-alt" style="font-size: 2rem; color: #10B981; margin-bottom: 1rem;"></i>
<h3>Secure</h3>
<p>Bank-level security for your data</p>
</div>
<div class="hero-card">
<i class="fas fa-bolt" style="font-size: 2rem; color: #F59E0B; margin-bottom: 1rem;"></i>
<h3>Fast</h3>
<p>Instant predictions in seconds</p>
</div>
</div>
</div>
</section>
</div>
""", unsafe_allow_html=True)
with st.container(key="navbtn"):
if st.button(" Start Predicting",key="pred"):
st.session_state.active_page = 'predictor'
st.rerun()
if st.button(" Learn More",key="abt"):
st.session_state.active_page = 'about'
st.rerun()
# We need to trigger the JS function to set active state and navigate
elif st.session_state.active_page == 'predictor':
# --- Prediction Form ---
# We use st.form to group all the inputs. When the submit button is pressed,
# Streamlit re-runs the script with all the new input values.
with st.container(key ="main-form" ):
st.markdown('<h2 class="section-title">Customer Financial Profile</h2>', unsafe_allow_html=True)
with st.form(key="prediction_form"):
# Create columns for the input grid layout
col1, col2, col3 = st.columns(3)
with col1:
reports = st.number_input("Major Derogatory Reports", min_value=0, max_value=20, value=0, help="Number of serious credit issues reported")
age = st.number_input("Age (years)", min_value=18.0, max_value=100.0, value=30.0, step=0.1, help="Customer's age in years")
income = st.number_input("Yearly Income ($10,000s)", min_value=0.0, max_value=100.0, value=3.0, step=0.1, help="Annual income in tens of thousands")
owner = st.selectbox("Home Owner", ('no', 'yes'), help="Does customer own their home?")
with col2:
card = st.selectbox("Card Owner", ('no', 'yes'), help="Does customer own a credit card?")
share = st.number_input("Monthly Expenditure Ratio", min_value=0.0, max_value=1.0, value=0.1, step=0.01, help="Ratio of monthly spending to yearly income")
active = st.number_input("Active Credit Accounts", min_value=0, max_value=50, value=5, help="Total number of active credit accounts")
selfemp = st.selectbox("Self Employed", ('no', 'yes'), help="Is the customer self-employed?")
with col3:
dependents = st.number_input("Number of Dependents", min_value=0, max_value=10, value=0, help="Financially dependent individuals")
months = st.number_input("Months at Current Address", min_value=0, max_value=500, value=36, help="Duration at current residence")
majorcards = st.number_input("Major Credit Cards", min_value=0, max_value=10, value=1, help="Number of major credit cards owned")
payments = st.number_input("Credit Card Payments", min_value=0, max_value=50, value=6, help="Total credit card payments made")
# The submit button for the form
submitted = st.form_submit_button("Predict Expenditure")
# --- Model Prediction Logic ---
# This block runs only when the form has been submitted.
if st.button("Dismiss modal", key="dismiss_modal_btn", help="Hidden dismiss button"):
st.session_state.show_prediction = False
st.rerun()
if submitted:
model = load_model()
if model is not None:
# Show a loading spinner while processing
with st.spinner("Analyzing financial data with AI..."):
time.sleep(1) # Simulate processing time
# Convert categorical inputs from 'yes'/'no' to 1/0 for the model
owner_encoded = 1 if owner == 'yes' else 0
card_encoded = 1 if card == 'yes' else 0
selfemp_encoded = 1 if selfemp == 'yes' else 0
# Create a pandas DataFrame with the exact structure the model expects
input_data = pd.DataFrame([{
'card': card, # "yes"/"no" as string
'reports': reports, # int
'age': age, # float
'income': income, # float
'share': share, # float
'owner': owner, # "yes"/"no" as string
'selfemp': selfemp, # "yes"/"no" as string
'dependents': dependents, # int
'months': months, # int
'majorcards': majorcards,
'active':active# int
# float or placeholder if unknown
}])
expected_features = model.feature_names_in_
# Filter and reorder the input columns to match the model
input_filtered = input_data[expected_features]
print("input_data",input_data)
print("expected",model.feature_names_in_) # If using scikit-learn 1.0+
print("input_data_type",input_data.dtypes)
try:
# Get the prediction from the model
prediction = model.predict(input_filtered)[0]
print("prediction:",prediction)
# Store the result and set the flag to show it
st.session_state.predicted_value = abs(prediction) # Ensure it's a positive number
st.session_state.show_prediction = True
except Exception as e:
st.error(f"Could not make a prediction. Error: {e}")
else:
st.error("The prediction model is not available. Please check server logs.")
# --- Display Prediction Result ---
# This block displays the result card if a prediction has been made.
if st.session_state.show_prediction:
st.markdown(f"""
<style>
/* Modal overlay */
.modal-overlay {{
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}}
/* Modal content */
.modal-content {{
background: #222;
padding: 2rem 3rem;
border-radius: 10px;
color: white;
max-width: 400px;
box-shadow: 0 0 15px rgba(0,0,0,0.5);
text-align: center;
position: relative;
}}
.result-label {{
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 0.5rem;
}}
.result-amount {{
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
}}
</style>
<div class="modal-overlay" id="modal-overlay">
<div class="modal-content" id="modal-content">
<div class="result-label">Predicted Monthly Expenditure</div>
<div class="result-amount">{st.session_state.predicted_value:,.2f}</div>
<p style="color: rgba(255, 255, 255, 0.7); margin-top: 1rem;">
Based on advanced machine learning analysis of financial patterns.
</p>
</div>
</div>
""",
unsafe_allow_html=True,
)
my_js = """
// Close modal if clicking outside the modal-content
const overlay = window.parent.document.getElementById("modal-overlay");
overlay.addEventListener("click", function(e) {{
if (e.target.id === "modal-overlay") {{
const btn = window.parent.document.querySelector('[class*="st-key-dismiss_modal_btn"]>div >div >div >div >button');
if (btn) {
btn.click();
}
//overlay.style.display = "none";
}}
}});
"""
my_html = f"<script>{my_js}</script>"
html(my_html)
# Features Page
elif st.session_state.active_page == 'features':
st.markdown("""
<div id="features" class="page active">
<div class="container">
<div class="page-header">
<h1>Powerful Features</h1>
<p>Discover what makes CreditIQ your ideal partner for financial insights.</p>
</div>
<div class="features-grid">
<div class="feature-card">
<i class="fas fa-chart-area feature-icon"></i>
<h3>Accurate Predictions</h3>
<p style="color: var(--gray-light);">Leverage state-of-the-art machine learning models for highly precise expenditure forecasts.</p>
</div>
<div class="feature-card">
<i class="fas fa-database feature-icon"></i>
<h3>Data Security</h3>
<p style="color: var(--gray-light);">Your financial data is protected with industry-leading encryption and security protocols.</p>
</div>
<div class="feature-card">
<i class="fas fa-user-shield feature-icon"></i>
<h3>Privacy Focused</h3>
<p style="color: var(--gray-light);">We prioritize your privacy with strict data handling and anonymity measures.</p>
</div>
<div class="feature-card">
<i class="fas fa-mobile-alt feature-icon"></i>
<h3>Responsive Design</h3>
<p style="color: var(--gray-light);">Access CreditIQ seamlessly on any device, from desktop to mobile.</p>
</div>
<div class="feature-card">
<i class="fas fa-lightbulb feature-icon"></i>
<h3>Actionable Insights</h3>
<p style="color: var(--gray-light);">Understand your spending habits and gain insights to optimize your finances.</p>
</div>
<div class="feature-card">
<i class="fas fa-cogs feature-icon"></i>
<h3>Customizable Models</h3>
<p style="color: var(--gray-light);">Tailor prediction models to fit unique financial scenarios and individual needs.</p>
</div>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# About Page
elif st.session_state.active_page == 'about':
st.markdown("""
<div id="about" class="page active">
<div class="container">
<div class="page-header">
<h1>About CreditIQ</h1>
<p>Our mission is to empower individuals and businesses with intelligent financial forecasting tools.</p>
</div>
<div class="about-content">
<div class="about-text">
<h2>Revolutionizing Financial Forecasting</h2>
<p>CreditIQ was founded on the principle that informed financial decisions lead to greater stability and growth. We believe that by providing highly accurate, AI-driven credit expenditure predictions, we can help our users better manage their budgets, identify trends, and plan for the future with confidence.</p>
<p>Our team of data scientists and financial experts has developed a robust platform that combines cutting-edge machine learning algorithms with user-friendly design. We are committed to continuous innovation and maintaining the highest standards of data security and privacy.</p>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number">99%</div>
<div style="color: var(--gray-light);">Accuracy Rate</div>
</div>
<div class="stat-card">
<div class="stat-number">1M+</div>
<div style="color: var(--gray-light);">Predictions Made</div>
</div>
</div>
</div>
<div class="about-visual">
<!-- Placeholder for an image or animated visual if desired -->
<img src="https://placehold.co/400x300/0c0c0c/1a1a1a?text=AI+Financials" alt="AI Financial Illustration" style="max-width: 100%; height: auto; border-radius: 16px; box-shadow: var(--shadow-md);">
</div>
</div>
</div>
</div>
""", unsafe_allow_html=True)
st.markdown(f"<script>showPage('about');</script>", unsafe_allow_html=True)
# Contact Page
elif st.session_state.active_page == 'contact':
st.markdown("""
<div id="contact" class="page active">
<div class="container">
<div class="page-header">
<h1>Get in Touch</h1>
<p>Have questions, feedback, or need support? We're here to help.</p>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# Inject Streamlit components into the Contact form
with st.container(key="contact-form"):
with st.form("contact_form",clear_on_submit=True):
st.text_input("Your Name", key="contact_name_input", help="Please enter your name.")
st.text_input("Your Email", key="contact_email_input", help="Please enter your email address.")
st.text_area("Message", key="contact_message_input", help="Type your message here.")
submittedcon = st.form_submit_button("Send Message", help="Click to send your message.")
if submittedcon :
st.success("Thank you for your message! We will get back to you soon.")