-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
139 lines (120 loc) · 4.33 KB
/
app.py
File metadata and controls
139 lines (120 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import streamlit as st
import pandas as pd
import joblib
import shap
import os
from datetime import datetime
# Config & Utils
from config.settings import (
APP_TITLE, APP_ICON, APP_VERSION,
DATA_PATH, RISK_MODEL_PATH, SEGMENT_MODEL_PATH, SCALER_PATH
)
from src.data_loader import load_data, clean_data
from src.features import FeatureEngineer
from src.model import RiskModel, SegmentModel
# UI Modules
from src.ui import dashboard, portfolio, risk_engine, customer_360, what_if, analytics
# Decision Intelligence
from src.decision_log import get_logger
# --- Configuration ---
st.set_page_config(
page_title=APP_TITLE,
page_icon=APP_ICON,
layout="wide",
initial_sidebar_state="expanded"
)
# --- Resource Loading ---
@st.cache_resource
def load_system():
if not os.path.exists(RISK_MODEL_PATH):
return None, None, None, None
try:
risk_model = RiskModel()
risk_model.load(RISK_MODEL_PATH)
segment_model = SegmentModel()
segment_model.load(SEGMENT_MODEL_PATH)
fe = joblib.load(SCALER_PATH)
# SHAP Explainer
explainer = shap.TreeExplainer(risk_model.model)
return risk_model, segment_model, fe, explainer
except Exception as e:
return None, None, None, None
@st.cache_data
def load_and_process_data():
try:
df = load_data(DATA_PATH)
df = clean_data(df)
return df
except Exception:
return pd.DataFrame()
# --- Main App Logic ---
def main():
# Load Resources
risk_model, segment_model, fe, explainer = load_system()
df = load_and_process_data()
if risk_model is None or df.empty:
st.error("System is initializing or data is missing. Please run the training script first.")
st.stop()
# Inference Pipeline
X_inference = fe.preprocess_for_inference(df)
df["Borrower_Segment"] = segment_model.predict(X_inference)
# NOTE: Cluster IDs are arbitrary. If model is retrained, verify these labels
# by analyzing cluster centroids (e.g., mean income, loan amount per cluster).
segment_mapping = {
0: "Moderate Income, High Burden",
1: "High Income, Low Risk",
2: "Moderate Income, Medium Risk",
3: "High Loan, High Risk",
}
df["Segment_Name"] = df["Borrower_Segment"].map(segment_mapping)
risk_probs = risk_model.predict_proba(X_inference)
df["Risk_Score"] = risk_probs[:, 1]
def strategy_rule(score):
if score > 0.75: return "Legal Action"
elif score > 0.50: return "Settlement Offer"
else: return "Standard Monitoring"
df["Recovery_Strategy"] = df["Risk_Score"].apply(strategy_rule)
df["Risk_Label"] = df["Risk_Score"].apply(lambda x: "High" if x > 0.5 else "Low")
# Log predictions (only on first load, not every rerun)
if 'predictions_logged' not in st.session_state:
logger = get_logger()
for _, row in df.head(10).iterrows(): # Sample to avoid log bloat
logger.log_prediction(
borrower_id=row['Borrower_ID'],
risk_score=row['Risk_Score'],
recommended_strategy=row['Recovery_Strategy'],
segment=row['Segment_Name']
)
st.session_state.predictions_logged = True
# Sidebar Navigation
with st.sidebar:
st.title("🏦 LoanGuard")
st.markdown("### Intelligent Recovery")
st.markdown("---")
page = st.radio("Navigation", [
"Dashboard Overview",
"Portfolio Management",
"Risk Analysis Engine",
"Customer 360",
"What-If Simulator",
"Analytics Hub"
])
st.markdown("---")
st.caption(f"System Status: Online")
st.caption(f"Last Sync: {datetime.now().strftime('%H:%M:%S')}")
st.caption(APP_VERSION)
# Router
if page == "Dashboard Overview":
dashboard.render(df)
elif page == "Portfolio Management":
portfolio.render(df)
elif page == "Risk Analysis Engine":
risk_engine.render(df)
elif page == "Customer 360":
customer_360.render(df, explainer, fe, X_inference)
elif page == "What-If Simulator":
what_if.render(df, risk_model, fe, explainer)
elif page == "Analytics Hub":
analytics.render(df, risk_model, fe)
if __name__ == "__main__":
main()