AsmaaElnagger commited on
Commit
6af334f
·
1 Parent(s): adabe36
.streamlit/config.toml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [server]
2
+ headless = true
3
+ enableCORS = false
4
+ port = 8501
5
+ enableXsrfProtection = false
6
+
7
+ [browser]
8
+ gatherUsageStats = false
9
+
10
+ [global]
11
+ disableWatchdogWarning = true
Dockerfile CHANGED
@@ -9,13 +9,16 @@ RUN apt-get update && apt-get install -y \
9
  git \
10
  && rm -rf /var/lib/apt/lists/*
11
 
12
- COPY requirements.txt ./
13
- COPY src/ ./src/
 
 
14
 
15
- RUN pip3 install -r requirements.txt
 
16
 
17
  EXPOSE 8501
18
 
19
- HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
20
 
21
- ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
9
  git \
10
  && rm -rf /var/lib/apt/lists/*
11
 
12
+ COPY requirements.txt /app
13
+ COPY download_model.py /app
14
+ COPY .streamlit/ /app/.streamlit/
15
+ COPY src/ /app/src/
16
 
17
+ RUN pip3 install --no-cache-dir -r requirements.txt
18
+ RUN python3 download_model.py
19
 
20
  EXPOSE 8501
21
 
22
+ HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1
23
 
24
+ ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
download_model.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import AutoModelForImageClassification, AutoImageProcessor
2
+
3
+ model_name = "Asmaa111/diabetic-eye"
4
+ save_path = "./diabetic_model"
5
+
6
+ model = AutoModelForImageClassification.from_pretrained(model_name)
7
+ processor = AutoImageProcessor.from_pretrained(model_name)
8
+
9
+ model.save_pretrained(save_path)
10
+ processor.save_pretrained(save_path)
requirements.txt CHANGED
@@ -1,3 +1,8 @@
1
  altair
2
  pandas
3
- streamlit
 
 
 
 
 
 
1
  altair
2
  pandas
3
+ streamlit
4
+ torch
5
+ transformers
6
+ Pillow
7
+ requests
8
+ pdf2image
src/streamlit_app.py CHANGED
@@ -1,40 +1,292 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import torch
3
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
4
+ from PIL import Image
5
+ import requests
6
+ from io import BytesIO
7
+ from pdf2image import convert_from_bytes
8
+ import json
9
+ import os
10
 
11
+ # تأكد أن Streamlit تستخدم مجلد .streamlit القابل للكتابة
12
+ os.environ["STREAMLIT_HOME"] = "/app/.streamlit"
13
+
14
+ # Load Lottie animation
15
+ def load_lottiefile(filepath: str):
16
+ if filepath.startswith(('http://', 'https://')):
17
+ response = requests.get(filepath)
18
+ response.raise_for_status()
19
+ return response.json()
20
+ else:
21
+ with open(filepath, "r") as f:
22
+ return json.load(f)
23
+
24
+ # Load the model and processor
25
+ # model_path = "Asmaa111/diabetic-eye" # new version
26
+ model_path = "./diabetic_model" # for space
27
+ # model_path = r"C:\Users\Milestone\dinov2-base-finetuned-eye"
28
+ # model_path = r"AsmaaElnagger/Diabetic_RetinoPathy_detection" # old version
29
+
30
+
31
+ @st.cache_resource
32
+ def load_model():
33
+
34
+ processor = AutoImageProcessor.from_pretrained(model_path)
35
+ model = AutoModelForImageClassification.from_pretrained(model_path)
36
+ model.eval()
37
+ return model, processor
38
+
39
+ def predict(image, model, processor):
40
+ inputs = processor(images=image, return_tensors="pt")
41
+ with torch.no_grad():
42
+ outputs = model(**inputs)
43
+ predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
44
+ predicted_class = predictions.argmax().item()
45
+ predicted_label = model.config.id2label[predicted_class]
46
+ return predicted_label
47
+
48
+ # App Config
49
+ st.set_page_config(
50
+ page_title="Diabetic Eye Classifier",
51
+ page_icon="👁️",
52
+ layout="wide"
53
+ )
54
+
55
+ # Custom CSS with animations
56
+ st.markdown("""
57
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
58
+ <style>
59
+ @keyframes fadeIn {
60
+ from { opacity: 0; transform: translateY(20px); }
61
+ to { opacity: 1; transform: translateY(0); }
62
+ }
63
+ .section {
64
+ padding: 4rem 0;
65
+ animation: fadeIn 0.8s ease-out;
66
+ }
67
+ .hero {
68
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
69
+ padding: 5rem 1rem;
70
+ border-radius: 10px;
71
+ margin-bottom: 3rem;
72
+ }
73
+ .feature-card {
74
+ padding: 2rem;
75
+ border-radius: 10px;
76
+ background: white;
77
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
78
+ height: 100%;
79
+ transition: transform 0.3s ease;
80
+ }
81
+ .feature-card:hover {
82
+ transform: translateY(-5px);
83
+ }
84
+ .team-card {
85
+ text-align: center;
86
+ padding: 1.5rem;
87
+ }
88
+ .testimonial-card {
89
+ padding: 2rem;
90
+ background: white;
91
+ border-radius: 10px;
92
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
93
+ margin-bottom: 1rem;
94
+ }
95
+ .icon {
96
+ font-size: 2.5rem;
97
+ margin-bottom: 1rem;
98
+ color: #4b6cb7;
99
+ }
100
+ .stButton>button {
101
+ transition: all 0.3s ease;
102
+ }
103
+ .stButton>button:hover {
104
+ transform: scale(1.02);
105
+ }
106
+ .medical-info {
107
+ background: #f0f8ff;
108
+ padding: 1.5rem;
109
+ border-radius: 10px;
110
+ margin: 1rem 0;
111
+ }
112
+ .image-section-prefix img{
113
+ height: 300px ! IMPORTANT;
114
+ max-width: 300px ! IMPORTANT;
115
+ text-align: center;
116
+ }
117
+ </style>
118
+ """, unsafe_allow_html=True)
119
+
120
+ # Hero Section with animation
121
+ with st.container():
122
+ st.markdown('<div class="hero">', unsafe_allow_html=True)
123
+ col1, col2 = st.columns([2, 1])
124
+ with col1:
125
+ st.title("👁️ Advanced Diabetic Retinopathy Screening")
126
+ st.markdown("""
127
+ **Revolutionizing** early detection of diabetic eye disease with **AI-powered** analysis.
128
+ Get instant preliminary screening results from retinal images.
129
+ """)
130
+
131
+ st.markdown('</div>', unsafe_allow_html=True)
132
+
133
+ # Medical Information Section
134
+ with st.container():
135
+ st.markdown('<div class="section">', unsafe_allow_html=True)
136
+ st.header("ℹ️ About Diabetic Retinopathy", anchor="about-dr")
137
+
138
+ with st.expander("What is Diabetic Retinopathy?"):
139
+ st.markdown("""
140
+ Diabetic retinopathy is a diabetes complication that affects eyes. It's caused by damage to the blood vessels
141
+ of the light-sensitive tissue at the back of the eye (retina). At first, diabetic retinopathy might cause no
142
+ symptoms or only mild vision problems. Eventually, it can cause blindness.
143
+ """)
144
+
145
+ with st.expander("Risk Factors"):
146
+ cols = st.columns(2)
147
+ with cols[0]:
148
+ st.markdown("""
149
+ - **Duration of diabetes**: The longer you have diabetes, the greater your risk
150
+ - **Poor blood sugar control**
151
+ - **High blood pressure**
152
+ - **High cholesterol**
153
+ """)
154
+ with cols[1]:
155
+ st.markdown("""
156
+ - **Pregnancy**
157
+ - **Tobacco use**
158
+ - **Being African-American, Hispanic or Native American**
159
+ """)
160
+
161
+ with st.expander("Prevention Tips"):
162
+ st.markdown("""
163
+ - **Manage your diabetes**: Keep your blood sugar levels in target range
164
+ - **Monitor your blood sugar levels**
165
+ - **Keep blood pressure and cholesterol under control**
166
+ - **Quit smoking**
167
+ - **Pay attention to vision changes**
168
+ - **Have regular eye exams**
169
+ """)
170
+ st.markdown('</div>', unsafe_allow_html=True)
171
+
172
+ # Features Section
173
+ with st.container():
174
+ st.markdown('<div class="section">', unsafe_allow_html=True)
175
+ st.header("✨ Key Features", anchor="features")
176
+ cols = st.columns(3)
177
+ features = [
178
+ {"icon": "fa-brain", "title": "AI-Powered Analysis",
179
+ "desc": "Our deep learning model provides accurate preliminary screening in seconds"},
180
+ {"icon": "fa-file-pdf", "title": "PDF Report Processing",
181
+ "desc": "Upload medical reports and we'll extract and analyze the images"},
182
+ {"icon": "fa-shield-alt", "title": "Secure & Private",
183
+ "desc": "HIPAA compliant processing with no data retention"}
184
+ ]
185
+ for i, col in enumerate(cols):
186
+ with col:
187
+ st.markdown(f"""
188
+ <div class="feature-card">
189
+ <div class="icon"><i class="fas {features[i]['icon']}"></i></div>
190
+ <h3>{features[i]['title']}</h3>
191
+ <p>{features[i]['desc']}</p>
192
+ </div>
193
+ """, unsafe_allow_html=True)
194
+ st.markdown('</div>', unsafe_allow_html=True)
195
+
196
+
197
+ # How It Works Section
198
+ with st.container():
199
+ st.markdown('<div class="section">', unsafe_allow_html=True)
200
+ st.header("🔍 How It Works", anchor="how-it-works")
201
+ steps = [
202
+ {"title": "1. Upload Image", "desc": "Provide a retinal image or PDF report"},
203
+ {"title": "2. AI Analysis", "desc": "Our model processes the image in seconds"},
204
+ {"title": "3. Get Results", "desc": "Receive preliminary screening results"}
205
+ ]
206
+ for step in steps:
207
+ with st.expander(step["title"]):
208
+ st.write(step["desc"])
209
+ st.markdown('</div>', unsafe_allow_html=True)
210
+
211
+
212
+ # Classifier Section
213
+ model, processor = load_model()
214
+
215
+ with st.container():
216
+ st.markdown('<div class="section">', unsafe_allow_html=True)
217
+ st.header("📷 Try Our Classifier", anchor="classifier")
218
+
219
+ col1, col2 = st.columns([1, 2])
220
+ with col1:
221
+ option = st.radio(
222
+ "Select input method:",
223
+ ("Upload Image/PDF", "Image URL"),
224
+ index=0
225
+ )
226
+
227
+ image = None
228
+ if option == "Upload Image/PDF":
229
+ uploaded_file = st.file_uploader(
230
+ "Choose file",
231
+ type=["jpg", "png", "jpeg", "pdf"],
232
+ label_visibility="collapsed"
233
+ )
234
+ if uploaded_file:
235
+ if uploaded_file.type == "application/pdf":
236
+ images = convert_from_bytes(uploaded_file.read())
237
+ if images:
238
+ image = images[0]
239
+ else:
240
+ image = Image.open(uploaded_file)
241
+ else:
242
+ url = st.text_input("Enter image URL", placeholder="https://example.com/image.jpg")
243
+ if url:
244
+ try:
245
+ response = requests.get(url)
246
+ image = Image.open(BytesIO(response.content))
247
+ except:
248
+ st.error("Invalid URL or image")
249
+
250
+ with col2:
251
+ if image:
252
+ st.image(image, width=600)
253
+ if st.button("Analyze Image", type="primary"):
254
+ with st.spinner("Analyzing..."):
255
+ prediction = predict(image, model, processor)
256
+ st.success(f"**Prediction:** {prediction}")
257
+ #st.balloons()
258
+ else:
259
+ st.info("Please upload an image or enter a URL to begin analysis")
260
+ st.markdown('</div>', unsafe_allow_html=True)
261
+
262
+ # Medical Disclaimer
263
+ with st.container():
264
+ st.markdown("""
265
+ <div class="medical-info">
266
+ <h4>Medical Disclaimer</h4>
267
+ <p>This tool provides preliminary screening only and is not a substitute for professional medical advice, diagnosis, or treatment.
268
+ Always seek the advice of your physician or other qualified health provider with any questions you may have regarding a medical condition.</p>
269
+ </div>
270
+ """, unsafe_allow_html=True)
271
+
272
+ # Footer
273
+ st.markdown("---")
274
+ cols = st.columns(3)
275
+ with cols[0]:
276
+ st.markdown("""
277
+ **Contact Us**
278
+ <i class="fas fa-envelope"></i> [email protected]
279
+ <i class="fas fa-phone"></i> (123) 456-7890
280
+ """, unsafe_allow_html=True)
281
+ with cols[1]:
282
+ st.markdown("""
283
+ **Quick Links**
284
+ [About DR](#about-dr)
285
+ [Features](#features)
286
+ [How It Works](#how-it-works)
287
+ """)
288
+ with cols[2]:
289
+ st.markdown("""
290
+ © 2025 Diabetic Eye Classifier
291
+ Medical AI Application
292
+ """)