Skip to content

Commit 10116f6

Browse files
Update app.py
1 parent f318f08 commit 10116f6

1 file changed

Lines changed: 101 additions & 124 deletions

File tree

app.py

Lines changed: 101 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
# ============================================================
2-
# Imports & global config
2+
# Imports & configuration
33
# ============================================================
44
import streamlit as st
55
import pandas as pd
6-
import joblib
76
import numpy as np
7+
import joblib
88
import plotly.graph_objects as go
9-
import warnings
109
from sklearn import set_config
10+
import warnings
1111

12-
# Keep pandas through pipeline (feature-name safety)
1312
set_config(transform_output="pandas")
1413
warnings.filterwarnings("ignore")
1514

1615
# ============================================================
17-
# Load trained pipeline
16+
# Load trained pipeline bundle
1817
# ============================================================
1918
@st.cache_resource
2019
def load_pipeline():
@@ -25,7 +24,7 @@ def load_pipeline():
2524
feature_names = bundle["feature_names"]
2625

2726
# ============================================================
28-
# Human-readable class labels
27+
# Class names (UNCHANGED – same as training)
2928
# ============================================================
3029
CLASS_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
# ============================================================
4140
FEATURE_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
# ============================================================
5857
st.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)")
6765
st.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
9991
input_df = pd.DataFrame([input_data], columns=feature_names)
10092

10193
# ============================================================
102-
# PREDICTION
94+
# ANALYSIS
10395
# ============================================================
10496
st.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
# ============================================================
227204
st.divider()
228-
st.caption("Pipeline-based ML • Plotly visualsClinical decision-support tool")
205+
st.caption("LightGBM Pipeline • Probability-driven interpretationEthical ML design")

0 commit comments

Comments
 (0)