11# ============================================================
2- # Imports & global config
2+ # Imports & configuration
33# ============================================================
44import streamlit as st
55import pandas as pd
6- import joblib
76import numpy as np
7+ import joblib
88import plotly .graph_objects as go
9- import warnings
109from sklearn import set_config
10+ import warnings
1111
12- # Keep pandas through pipeline (feature-name safety)
1312set_config (transform_output = "pandas" )
1413warnings .filterwarnings ("ignore" )
1514
1615# ============================================================
17- # Load trained pipeline
16+ # Load trained pipeline bundle
1817# ============================================================
1918@st .cache_resource
2019def load_pipeline ():
@@ -25,7 +24,7 @@ def load_pipeline():
2524feature_names = bundle ["feature_names" ]
2625
2726# ============================================================
28- # Human-readable class labels
27+ # Class names (UNCHANGED – same as training)
2928# ============================================================
3029CLASS_MAP = {
3130 0 : "Healthy Liver" ,
@@ -36,7 +35,7 @@ def load_pipeline():
3635}
3736
3837# ============================================================
39- # Medical-grade UI configuration
38+ # UI metadata for inputs
4039# ============================================================
4140FEATURE_UI = {
4241 "age" : {"label" : "Age (years)" , "min" : 1 , "max" : 100 , "default" : 32 },
@@ -48,22 +47,21 @@ def load_pipeline():
4847 "cholinesterase" : {"label" : "Cholinesterase (U/L)" , "min" : 2000 , "max" : 12000 , "default" : 7000 },
4948 "cholesterol" : {"label" : "Cholesterol (mg/dL)" , "min" : 80 , "max" : 400 , "default" : 170 },
5049 "creatinina" : {"label" : "Creatinine (mg/dL)" , "min" : 0.3 , "max" : 5.0 , "default" : 0.9 },
51- "gamma glutamyl transferase" : {"label" : "GGT – Gamma GT (U/L)" , "min" : 5 , "max" : 300 , "default" : 30 },
50+ "gamma glutamyl transferase" : {"label" : "Gamma GT (U/L)" , "min" : 5 , "max" : 300 , "default" : 30 },
5251 "protein" : {"label" : "Total Protein (g/dL)" , "min" : 4.0 , "max" : 9.0 , "default" : 7.2 },
5352}
5453
5554# ============================================================
56- # Page config
55+ # Page setup
5756# ============================================================
5857st .set_page_config (
59- page_title = "Liver Health AI " ,
58+ page_title = "Liver Disease Pattern Analysis " ,
6059 page_icon = "🩺" ,
6160 layout = "centered"
6261)
6362
64- st .title ("🩺 Liver Health AI Dashboard" )
65- st .caption ("Clinical inputs → ML pipeline → visual decision support" )
66-
63+ st .title ("🩺 Liver Disease Pattern Analysis System" )
64+ st .caption ("ML-based pattern similarity & risk leaning (not a diagnosis)" )
6765st .divider ()
6866
6967# ============================================================
@@ -78,151 +76,130 @@ def load_pipeline():
7876 key = feature .lower ()
7977
8078 with cols [i % 2 ]:
81-
82- # Sex (human-friendly)
8379 if key in ["sex" , "gender" ]:
8480 sex = st .selectbox ("Sex" , ["Male" , "Female" ])
8581 input_data [feature ] = 1 if sex == "Male" else 0
86-
87- # Numeric features
8882 else :
8983 ui = FEATURE_UI .get (key , {})
9084 input_data [feature ] = st .number_input (
9185 label = ui .get ("label" , feature .replace ("_" , " " ).title ()),
9286 min_value = ui .get ("min" , 0.0 ),
9387 max_value = ui .get ("max" , 1000.0 ),
9488 value = ui .get ("default" , 1.0 ),
95- help = "Enter raw lab value (no transformation needed)"
9689 )
9790
98- # Preserve feature order
9991input_df = pd .DataFrame ([input_data ], columns = feature_names )
10092
10193# ============================================================
102- # PREDICTION
94+ # ANALYSIS
10395# ============================================================
10496st .divider ()
10597
106- if st .button ("🔍 Analyze Liver Health " ):
98+ if st .button ("🔍 Analyze Pattern " ):
10799
108100 probs = pipeline .predict_proba (input_df )[0 ]
109101 pred_class = int (np .argmax (probs ))
110102 confidence = float (probs [pred_class ])
111- disease = CLASS_MAP [pred_class ]
112-
113- # Risk bucket
114- if confidence < 0.45 :
115- risk = "Low"
116- risk_color = "green"
117- elif confidence < 0.75 :
118- risk = "Medium"
119- risk_color = "orange"
120- else :
121- risk = "High"
122- risk_color = "red"
103+
104+ st .success (f"### 🧾 Primary Model Output: **{ CLASS_MAP [pred_class ]} **" )
105+ st .info (f"Model Confidence: **{ confidence :.2%} **" )
106+
107+ st .divider ()
108+ st .subheader ("📊 Disease Pattern Leaning" )
123109
124110 # ========================================================
125- # RESULT SUMMARY
111+ # 1️⃣ Disease Leaning Chart
126112 # ========================================================
127- st .success (f"### 🧾 Diagnosis: **{ disease } **" )
128- st .info (f"Confidence: **{ confidence :.2%} ** | Risk Level: **{ risk } **" )
113+ focus = {
114+ "Healthy Liver" : 0 ,
115+ "Cirrhosis" : 1 ,
116+ "Hepatitis" : 2 ,
117+ "Fibrosis" : 3 ,
118+ "Suspected Liver Disorder" : 4 ,
119+ }
120+
121+ labels = list (focus .keys ())
122+ values = [probs [focus [l ]] for l in labels ]
123+
124+ fig = go .Figure (
125+ data = [
126+ go .Bar (
127+ x = labels ,
128+ y = values ,
129+ marker_color = [
130+ "#2ecc71" , # Healthy
131+ "#e74c3c" , # Cirrhosis
132+ "#f39c12" , # Hepatitis
133+ "#d35400" , # Fibrosis
134+ "#9b59b6" , # Suspected
135+ ]
136+ )
137+ ]
138+ )
129139
130- st .divider ()
131- st .subheader ("📊 Visual Health Analysis" )
140+ fig .update_layout (
141+ title = "Disease Pattern Similarity (Probability Distribution)" ,
142+ yaxis = dict (range = [0 , 1 ], title = "Probability" ),
143+ xaxis_title = "Disease Pattern" ,
144+ )
145+
146+ st .plotly_chart (fig , use_container_width = True )
132147
133148 # ========================================================
134- # DASHBOARD (2 × 2)
149+ # 2️⃣ Lean Strength toward Fibrosis / Suspected
135150 # ========================================================
136- col1 , col2 = st .columns (2 )
137-
138- # ---- Chart 1: Risk Gauge ----
139- with col1 :
140- fig1 = go .Figure (go .Indicator (
141- mode = "gauge+number" ,
142- value = confidence * 100 ,
143- number = {"suffix" : "%" },
144- title = {"text" : "Overall Risk Confidence" },
145- gauge = {
146- "axis" : {"range" : [0 , 100 ]},
147- "bar" : {"color" : risk_color },
148- "steps" : [
149- {"range" : [0 , 45 ], "color" : "#b6f2c2" },
150- {"range" : [45 , 75 ], "color" : "#ffeaa7" },
151- {"range" : [75 , 100 ], "color" : "#fab1a0" },
152- ],
153- },
154- ))
155- st .plotly_chart (fig1 , use_container_width = True )
156-
157- # ---- Chart 2: Top-2 Probabilities ----
158- with col2 :
159- top_idx = np .argsort (probs )[- 2 :][::- 1 ]
160- fig2 = go .Figure (
161- data = [
162- go .Bar (
163- x = [CLASS_MAP [i ] for i in top_idx ],
164- y = probs [top_idx ],
165- marker_color = ["#0984e3" , "#6c5ce7" ]
166- )
167- ]
168- )
169- fig2 .update_layout (
170- title = "Most Likely Conditions" ,
171- yaxis = dict (range = [0 , 1 ], title = "Probability" ),
172- )
173- st .plotly_chart (fig2 , use_container_width = True )
174-
175- col3 , col4 = st .columns (2 )
176-
177- # ---- Chart 3: Feature Profile ----
178- with col3 :
179- values = np .array ([float (input_data [f ]) for f in feature_names ])
180- normalized = values / (np .mean (values ) + 1e-6 )
181-
182- fig3 = go .Figure (
183- data = [go .Bar (x = list (range (len (normalized ))), y = normalized )]
184- )
185- fig3 .add_hline (y = 1 , line_dash = "dash" )
186- fig3 .update_layout (
187- title = "Overall Feature Profile (Relative Scale)" ,
188- xaxis_title = "Feature Index" ,
189- yaxis_title = "Relative Magnitude" ,
190- )
191- st .plotly_chart (fig3 , use_container_width = True )
192-
193- # ---- Chart 4: Top Feature Deviations ----
194- with col4 :
195- deviations = np .abs (normalized - 1.0 )
196- top_k = np .argsort (deviations )[- 5 :][::- 1 ]
197-
198- fig4 = go .Figure (
199- data = [
200- go .Bar (
201- x = [feature_names [i ].replace ("_" , " " ) for i in top_k ],
202- y = deviations [top_k ],
203- marker_color = "#d63031"
204- )
205- ]
206- )
207- fig4 .update_layout (
208- title = "Top Influential Feature Deviations" ,
209- yaxis_title = "Deviation Strength" ,
210- )
211- st .plotly_chart (fig4 , use_container_width = True )
151+ fibrosis_prob = probs [3 ]
152+ suspected_prob = probs [4 ]
153+ lean_strength = fibrosis_prob + suspected_prob
154+
155+ st .subheader ("📌 Chronic Pattern Lean Strength" )
156+
157+ st .metric (
158+ label = "Fibrosis + Suspected Similarity" ,
159+ value = f"{ lean_strength :.2%} "
160+ )
212161
213162 # ========================================================
214- # AI INTERPRETATION
163+ # 3️⃣ Recommendation Engine (Probability-based)
215164 # ========================================================
216- st .subheader ("💬 AI Interpretation" )
165+ st .subheader ("🩺 Clinical Recommendation (Decision Support)" )
166+
217167 with st .chat_message ("assistant" ):
218- st .write (
219- f"The model predicts **{ disease } ** with **{ confidence :.2%} confidence**. "
220- f"The risk level is **{ risk .lower ()} **, based on learned interactions across multiple biomarkers. "
221- "This enables early detection even when individual lab values appear normal."
222- )
168+
169+ if lean_strength >= 0.80 :
170+ st .write (
171+ "🔴 **Strong leaning toward chronic liver disease patterns detected.**\n \n "
172+ "The patient's biomarker profile closely resembles historical patterns "
173+ "associated with **fibrosis or early chronic liver disorders**.\n \n "
174+ "✅ **Recommendation:** Prompt clinical evaluation is advised, including "
175+ "advanced liver assessment (e.g., FibroScan, imaging, specialist referral)."
176+ )
177+
178+ elif lean_strength >= 0.50 :
179+ st .write (
180+ "🟠 **Moderate leaning toward fibrotic or suspected patterns.**\n \n "
181+ "Some biomarkers show early deviations commonly seen in progressive liver conditions.\n \n "
182+ "✅ **Recommendation:** Regular monitoring, repeat liver function tests, "
183+ "and lifestyle risk assessment are recommended."
184+ )
185+
186+ else :
187+ st .write (
188+ "🟢 **Low similarity to fibrotic or suspected disease patterns.**\n \n "
189+ "The current biomarker profile does not strongly align with chronic liver disease patterns.\n \n "
190+ "✅ **Recommendation:** Continue routine health check-ups and preventive care."
191+ )
192+
193+ # ========================================================
194+ # Transparency note
195+ # ========================================================
196+ st .caption (
197+ "⚠️ This system performs statistical pattern analysis based on historical data. "
198+ "It does not provide a medical diagnosis and should be used only as decision-support."
199+ )
223200
224201# ============================================================
225- # FOOTER
202+ # Footer
226203# ============================================================
227204st .divider ()
228- st .caption ("Pipeline-based ML • Plotly visuals • Clinical decision-support tool " )
205+ st .caption ("LightGBM Pipeline • Probability-driven interpretation • Ethical ML design " )
0 commit comments