CoolFace
Apppublic

Natzi21/malaria-cell-detection

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
app.py316 linesDownload Raw Back to root
1"""
2Malaria Detection - Streamlit App
3===================================
4AI-powered blood smear analysis.
5Run with: streamlit run app.py
6"""
7
8import streamlit as st
9import tensorflow as tf
10import numpy as np
11from PIL import Image
12import time
13import datetime
14
15# ─────────────────────────────────────────────
16#  PAGE CONFIG
17# ─────────────────────────────────────────────
18st.set_page_config(
19    page_title="Malaria Detection System",
20    page_icon="🦟",
21    layout="centered"
22)
23
24# ─────────────────────────────────────────────
25#  CUSTOM CSS
26# ─────────────────────────────────────────────
27st.markdown("""
28<style>
29    @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Inter:wght@300;400;600;700&display=swap');
30
31    html, body, [class*="css"] {
32        font-family: 'Inter', sans-serif;
33    }
34
35    .stApp {
36        background-color: #0d1117;
37        color: #e6edf3;
38    }
39
40    .main-header {
41        text-align: center;
42        padding: 2rem 0 1rem;
43    }
44
45    .badge {
46        display: inline-block;
47        background: linear-gradient(90deg, #238636, #2ea043);
48        color: white;
49        padding: 4px 16px;
50        border-radius: 20px;
51        font-size: 0.75rem;
52        font-weight: 700;
53        letter-spacing: 2px;
54        margin-bottom: 12px;
55        font-family: 'Space Mono', monospace;
56    }
57
58    .main-title {
59        font-size: 2.2rem;
60        font-weight: 700;
61        color: #e6edf3;
62        margin: 0;
63    }
64
65    .subtitle {
66        color: #8b949e;
67        font-size: 0.95rem;
68        margin-top: 8px;
69    }
70
71    .stat-container {
72        background: #161b22;
73        border: 1px solid #30363d;
74        border-radius: 12px;
75        padding: 1.2rem;
76        text-align: center;
77        margin-bottom: 1rem;
78    }
79
80    .stat-value {
81        font-size: 1.6rem;
82        font-weight: 700;
83        color: #58a6ff;
84        font-family: 'Space Mono', monospace;
85    }
86
87    .stat-label {
88        font-size: 0.72rem;
89        color: #8b949e;
90        margin-top: 4px;
91        letter-spacing: 0.5px;
92    }
93
94    .result-infected {
95        background: rgba(248, 81, 73, 0.1);
96        border: 1px solid rgba(248, 81, 73, 0.4);
97        border-radius: 12px;
98        padding: 1.5rem;
99        text-align: center;
100    }
101
102    .result-healthy {
103        background: rgba(46, 160, 67, 0.1);
104        border: 1px solid rgba(46, 160, 67, 0.4);
105        border-radius: 12px;
106        padding: 1.5rem;
107        text-align: center;
108    }
109
110    .result-title {
111        font-size: 1.4rem;
112        font-weight: 700;
113        margin: 0.5rem 0;
114    }
115
116    .result-infected .result-title { color: #f85149; }
117    .result-healthy  .result-title { color: #2ea043; }
118
119    .result-meta {
120        color: #8b949e;
121        font-size: 0.85rem;
122        font-family: 'Space Mono', monospace;
123    }
124
125    .history-item {
126        background: #161b22;
127        border: 1px solid #30363d;
128        border-radius: 8px;
129        padding: 0.75rem 1rem;
130        margin-bottom: 0.5rem;
131        display: flex;
132        justify-content: space-between;
133        font-size: 0.85rem;
134    }
135
136    .stButton > button {
137        background: linear-gradient(90deg, #1f6feb, #388bfd) !important;
138        color: white !important;
139        border: none !important;
140        border-radius: 8px !important;
141        font-weight: 600 !important;
142        padding: 0.6rem 2rem !important;
143        width: 100% !important;
144        font-size: 1rem !important;
145    }
146
147    .divider {
148        border: none;
149        border-top: 1px solid #21262d;
150        margin: 1.5rem 0;
151    }
152</style>
153""", unsafe_allow_html=True)
154
155# ─────────────────────────────────────────────
156#  SESSION STATE
157# ─────────────────────────────────────────────
158if "history" not in st.session_state:
159    st.session_state.history = []
160if "total_latency" not in st.session_state:
161    st.session_state.total_latency = 0
162
163# ─────────────────────────────────────────────
164#  LOAD MODEL (cached so it only loads once)
165# ─────────────────────────────────────────────
166@st.cache_resource
167def load_model():
168    from keras.layers import Dense
169
170    class PatchedDense(Dense):
171        def __init__(self, *args, **kwargs):
172            kwargs.pop('quantization_config', None)
173            super().__init__(*args, **kwargs)
174
175    model = tf.keras.models.load_model(
176        'malaria_model_final.h5',
177        custom_objects={'Dense': PatchedDense},
178        compile=False
179    )
180    return model
181
182IMG_SIZE = (128, 128)
183
184# ─────────────────────────────────────────────
185#  HEADER
186# ─────────────────────────────────────────────
187st.markdown("""
188<div class="main-header">
189    <div class="badge">⚡ 5G ENABLED</div>
190    <div class="main-title">🦟 Malaria Detection System</div>
191    <div class="subtitle">AI-powered blood smear analysis · MobileNetV2</div>
192</div>
193""", unsafe_allow_html=True)
194
195# ─────────────────────────────────────────────
196#  STATS BAR
197# ─────────────────────────────────────────────
198total = len(st.session_state.history)
199avg_latency = round(st.session_state.total_latency / total) if total > 0 else 0
200
201col1, col2, col3, col4 = st.columns(4)
202with col1:
203    st.markdown('<div class="stat-container"><div class="stat-value">94.3%</div><div class="stat-label">MODEL ACCURACY</div></div>', unsafe_allow_html=True)
204with col2:
205    st.markdown('<div class="stat-container"><div class="stat-value">0.9846</div><div class="stat-label">AUC-ROC SCORE</div></div>', unsafe_allow_html=True)
206with col3:
207    st.markdown(f'<div class="stat-container"><div class="stat-value">{total}</div><div class="stat-label">TOTAL PREDICTIONS</div></div>', unsafe_allow_html=True)
208with col4:
209    latency_display = f"{avg_latency}ms" if total > 0 else "—"
210    st.markdown(f'<div class="stat-container"><div class="stat-value">{latency_display}</div><div class="stat-label">AVG LATENCY</div></div>', unsafe_allow_html=True)
211
212st.markdown('<hr class="divider">', unsafe_allow_html=True)
213
214# ─────────────────────────────────────────────
215#  UPLOAD + PREDICT
216# ─────────────────────────────────────────────
217st.markdown("#### 🔬 Upload Blood Smear Image")
218st.write("Uploader Test")
219
220uploaded_file = st.file_uploader(
221    "Upload",
222    type=["png", "jpg", "jpeg"]
223)
224
225if uploaded_file:
226    st.success("File received!")
227    st.write(uploaded_file.name)
228
229if uploaded_file:
230    col_img, col_info = st.columns([1, 2])
231    with col_img:
232        img = Image.open(uploaded_file).convert("RGB")
233        st.image(img, caption="Uploaded image", use_container_width=True)
234    with col_info:
235        st.markdown(f"""
236        **File:** `{uploaded_file.name}`  
237        **Size:** `{img.size[0]} × {img.size[1]} px`  
238        **Format:** `{uploaded_file.type}`
239        """)
240        st.markdown(" ")
241        analyze = st.button("🚀 Analyze via 5G Network")
242
243    if analyze:
244        model = load_model()
245
246        with st.spinner("Transmitting over 5G network... Running AI analysis..."):
247            start = time.time()
248
249            img_resized = img.resize(IMG_SIZE)
250            img_array = np.array(img_resized) / 255.0
251            img_array = np.expand_dims(img_array, axis=0)
252
253            prob = float(model.predict(img_array, verbose=0)[0][0])
254            latency_ms = round((time.time() - start) * 1000)
255
256        prediction = "Parasitized" if prob > 0.5 else "Uninfected"
257        confidence = prob if prob > 0.5 else 1 - prob
258        timestamp = datetime.datetime.now().strftime("%H:%M:%S")
259
260        st.session_state.history.insert(0, {
261            "prediction": prediction,
262            "confidence": f"{confidence:.1%}",
263            "latency_ms": latency_ms,
264            "timestamp": timestamp,
265        })
266        st.session_state.total_latency += latency_ms
267
268        st.markdown('<hr class="divider">', unsafe_allow_html=True)
269
270        if prediction == "Parasitized":
271            st.markdown(f"""
272            <div class="result-infected">
273                <div style="font-size:3rem">🦟</div>
274                <div class="result-title">Malaria Detected — Parasitized</div>
275                <div class="result-meta">Confidence: {confidence:.1%} &nbsp;·&nbsp; Latency: {latency_ms}ms &nbsp;·&nbsp; {timestamp}</div>
276            </div>
277            """, unsafe_allow_html=True)
278        else:
279            st.markdown(f"""
280            <div class="result-healthy">
281                <div style="font-size:3rem">✅</div>
282                <div class="result-title">No Malaria — Uninfected</div>
283                <div class="result-meta">Confidence: {confidence:.1%} &nbsp;·&nbsp; Latency: {latency_ms}ms &nbsp;·&nbsp; {timestamp}</div>
284            </div>
285            """, unsafe_allow_html=True)
286
287        st.markdown(" ")
288        st.progress(confidence, text=f"Confidence: {confidence:.1%}")
289
290        st.rerun()
291
292# ─────────────────────────────────────────────
293#  PREDICTION HISTORY
294# ─────────────────────────────────────────────
295st.markdown('<hr class="divider">', unsafe_allow_html=True)
296st.markdown("#### 📋 Prediction History")
297
298if not st.session_state.history:
299    st.markdown('<p style="color:#8b949e; font-size:0.9rem;">No predictions yet. Upload an image to begin.</p>', unsafe_allow_html=True)
300else:
301    for entry in st.session_state.history:
302        is_infected = entry["prediction"] == "Parasitized"
303        dot_color = "#f85149" if is_infected else "#2ea043"
304        label = "🦟 Parasitized" if is_infected else "✅ Uninfected"
305        st.markdown(f"""
306        <div class="history-item">
307            <span>
308                <span style="display:inline-block;width:10px;height:10px;border-radius:50%;
309                      background:{dot_color};margin-right:8px;vertical-align:middle;"></span>
310                <strong>{label}</strong>
311            </span>
312            <span style="color:#8b949e;">{entry['confidence']} confidence</span>
313            <span style="color:#8b949e;font-family:'Space Mono',monospace;">{entry['latency_ms']}ms</span>
314            <span style="color:#6e7681;">{entry['timestamp']}</span>
315        </div>
316        """, unsafe_allow_html=True)