Files changed (1) hide show
  1. app.py +41 -242
app.py CHANGED
@@ -1,243 +1,42 @@
1
  import streamlit as st
2
- from PIL import Image
3
- from ultralytics import YOLO
4
- import cv2, os
5
- from datetime import datetime
6
- import numpy as np
7
- from dotenv import load_dotenv
8
- import irm_cancer_module
9
-
10
- # ---------------- Charger config ----------------
11
- load_dotenv()
12
- SAVE_LIMIT_FREE = int(os.getenv("SAVE_LIMIT_FREE", 5))
13
- PREMIUM_KEY = os.getenv("PREMIUM_KEY", "VOTRE_CLE_PREMIUM")
14
-
15
- # ---------------- Config générale ----------------
16
- MODEL_PATH = "best.pt"
17
- MODEL_IRM_PATH = "best_seg.pt"
18
- MODEL_STROKE_PATH = "stroke.pt"
19
- SAVE_DIR = os.path.join("/tmp", "results")
20
- os.makedirs(SAVE_DIR, exist_ok=True)
21
-
22
- # ---------------- Charger modèles YOLO ----------------
23
- model = YOLO(MODEL_PATH)
24
- model_irm = YOLO(MODEL_IRM_PATH)
25
- model_stroke = YOLO(MODEL_STROKE_PATH)
26
-
27
- # ---------------- Etat utilisateur ----------------
28
- for key in ["uploads_count", "uploads_count_irm", "uploads_count_stroke", "premium_access"]:
29
- if key not in st.session_state:
30
- st.session_state[key] = 0 if "count" in key else False
31
-
32
- # ---------------- Fonctions utilitaires ----------------
33
- def _largest_face_bbox(np_img):
34
- import mediapipe as mp
35
- mp_face_detection = mp.solutions.face_detection
36
- h, w = np_img.shape[:2]
37
- with mp_face_detection.FaceDetection(min_detection_confidence=0.6) as fd:
38
- results = fd.process(cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR))
39
- if not results.detections:
40
- return None
41
- boxes = []
42
- for det in results.detections:
43
- rel = det.location_data.relative_bounding_box
44
- x1 = int(max(0, rel.xmin) * w)
45
- y1 = int(max(0, rel.ymin) * h)
46
- x2 = int(min(1.0, rel.xmin + rel.width) * w)
47
- y2 = int(min(1.0, rel.ymin + rel.height) * h)
48
- boxes.append((x1, y1, x2, y2))
49
- boxes.sort(key=lambda b: (b[2]-b[0])*(b[3]-b[1]), reverse=True)
50
- return boxes[0] if boxes else None
51
-
52
- def check_limit(counter_name="uploads_count"):
53
- """Vérifie la limite gratuite."""
54
- if not st.session_state.premium_access and st.session_state[counter_name] >= SAVE_LIMIT_FREE:
55
- st.warning(f"⚠️ Limite gratuite atteinte ({SAVE_LIMIT_FREE} uploads). Passez en mode premium pour continuer.")
56
- return False
57
- return True
58
-
59
- # ---------------- Prédiction image classique ----------------
60
- def predict_image(image, conf=0.85, show_labels=True):
61
- if not check_limit("uploads_count"):
62
- return None
63
- np_img = np.array(image)
64
- face_bbox = _largest_face_bbox(np_img)
65
- if face_bbox is None:
66
- st.warning("⚠️ Aucun visage humain détecté. Veuillez centrer le visage.")
67
- return None
68
- if np_img.shape[2] == 4:
69
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
70
- else:
71
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
72
- results = model.predict(source=np_img, conf=conf, verbose=False)
73
- if len(results[0].boxes) == 0:
74
- return None
75
- annotated_image = results[0].plot(labels=show_labels)
76
- out_path = os.path.join(SAVE_DIR, f"image_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
77
- cv2.imwrite(out_path, annotated_image)
78
- st.session_state.uploads_count += 1
79
- return out_path
80
-
81
- # ---------------- Prédiction vidéo ----------------
82
- def predict_video(video_path, conf=0.85, show_labels=True):
83
- if not check_limit("uploads_count"):
84
- return None
85
- cap = cv2.VideoCapture(video_path)
86
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
87
- out_path = os.path.join(SAVE_DIR, f"video_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4")
88
- fps = cap.get(cv2.CAP_PROP_FPS) or 30
89
- width, height = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
90
- out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
91
- detections = 0
92
- while cap.isOpened():
93
- ret, frame = cap.read()
94
- if not ret:
95
- break
96
- results = model.predict(frame, conf=conf, verbose=False)
97
- if len(results[0].boxes) > 0:
98
- detections += 1
99
- annotated = results[0].plot(labels=show_labels)
100
- out.write(annotated)
101
- cap.release()
102
- out.release()
103
- if detections == 0:
104
- return None
105
- st.session_state.uploads_count += 1
106
- return out_path
107
-
108
- # ---------------- Prédiction IRM ----------------
109
- def predict_image_irm(image, conf=0.8, show_labels=True):
110
- if not check_limit("uploads_count_irm"):
111
- return None
112
- np_img = np.array(image)
113
- if np_img.shape[2] == 4:
114
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
115
- else:
116
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
117
- results = model_irm.predict(source=np_img, conf=conf, verbose=False)
118
- if results[0].masks is None or len(results[0].masks.data) == 0:
119
- st.warning("⚠️ Aucun masque détecté par le modèle IRM.")
120
- return None
121
- annotated_image = results[0].plot(labels=show_labels)
122
- out_path = os.path.join(SAVE_DIR, f"irm_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
123
- cv2.imwrite(out_path, annotated_image)
124
- st.session_state.uploads_count_irm += 1
125
- return out_path
126
-
127
- # ---------------- Prédiction Stroke IRM ----------------
128
- def predict_image_stroke(image, conf=0.8, show_labels=True):
129
- if not check_limit("uploads_count_stroke"):
130
- return None
131
- np_img = np.array(image)
132
- if np_img.shape[2] == 4:
133
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGBA2BGR)
134
- else:
135
- np_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
136
- results = model_stroke.predict(source=np_img, conf=conf, verbose=False)
137
- if len(results[0].boxes) == 0:
138
- st.warning("⚠️ Aucun AVC détecté par le modèle Stroke.")
139
- return None
140
- annotated_image = results[0].plot(labels=show_labels)
141
- out_path = os.path.join(SAVE_DIR, f"stroke_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
142
- cv2.imwrite(out_path, annotated_image)
143
- st.session_state.uploads_count_stroke += 1
144
- return out_path
145
-
146
- # ---------------- Interface Streamlit ----------------
147
- st.title("🧠 Stroke-IA Détection AVC par IA")
148
-
149
- # ---------------- Sidebar ----------------
150
- st.sidebar.header("⚙️ Paramètres utilisateur")
151
- conf_threshold = st.sidebar.slider("Seuil de confiance (images/vidéos)", 0.1, 1.0, 0.85, 0.05, key="conf_slider")
152
- conf_threshold_irm = st.sidebar.slider("Seuil de confiance (IRM)", 0.1, 1.0, 0.8, 0.05, key="conf_slider_irm")
153
- conf_threshold_stroke = st.sidebar.slider("Seuil de confiance (Stroke IRM)", 0.1, 1.0, 0.8, 0.05, key="conf_slider_stroke")
154
- show_labels = st.sidebar.checkbox("Afficher les labels", value=True, key="labels_checkbox")
155
-
156
- st.sidebar.header("🔑 Premium / Essai")
157
- if not st.session_state.premium_access:
158
- user_key = st.sidebar.text_input("Entrez votre clé premium :", type="password", key="premium_input")
159
- if user_key == PREMIUM_KEY:
160
- st.session_state.premium_access = True
161
- st.sidebar.success("✅ Mode premium activé ! La limitation est levée.")
162
- st.rerun()
163
-
164
- if not st.session_state.premium_access:
165
- st.sidebar.info(f"📊 Utilisation gratuite images/vidéos : {st.session_state.uploads_count}/{SAVE_LIMIT_FREE}")
166
- st.sidebar.info(f"📊 Utilisation gratuite IRM : {st.session_state.uploads_count_irm}/{SAVE_LIMIT_FREE}")
167
- st.sidebar.info(f"📊 Utilisation gratuite Stroke IRM : {st.session_state.uploads_count_stroke}/{SAVE_LIMIT_FREE}")
168
-
169
- # ---------------- Upload vidéo ----------------
170
- st.header("🎥 Détection sur vidéo")
171
- video_file = st.file_uploader("Uploader une vidéo", type=["mp4", "mov"], key="video_uploader")
172
- if video_file and st.button("Analyser la vidéo", key="video_button"):
173
- temp_path = os.path.join(SAVE_DIR, "temp_video.mp4")
174
- with open(temp_path, "wb") as f:
175
- f.write(video_file.read())
176
- result_path = predict_video(temp_path, conf=conf_threshold, show_labels=show_labels)
177
- if result_path is None:
178
- st.success("✅ Aucun AVC détecté ou limite gratuite atteinte.")
179
- else:
180
- st.video(result_path)
181
-
182
- # ---------------- Upload image ----------------
183
- st.header("🖼️ Détection sur image")
184
- image_file = st.file_uploader("Uploader une image", type=["jpg", "jpeg", "png"], key="image_uploader")
185
- if image_file and st.button("Analyser l'image", key="image_button"):
186
- image = Image.open(image_file)
187
- result_path = predict_image(image, conf=conf_threshold, show_labels=show_labels)
188
- if result_path is None:
189
- st.success("✅ Aucun AVC détecté ou limite gratuite atteinte.")
190
- else:
191
- st.image(result_path, caption="Image annotée", use_container_width=True)
192
-
193
- # ---------------- Upload IRM ----------------
194
- st.header("🧠 Détection CANCER par IRM")
195
- irm_file = st.file_uploader("Uploader une IRM", type=["jpg", "jpeg", "png"], key="irm_uploader")
196
- if irm_file and st.button("Analyser l'IRM", key="irm_button"):
197
- irm_image = Image.open(irm_file)
198
- result_path_irm = predict_image_irm(irm_image, conf=conf_threshold_irm, show_labels=show_labels)
199
- if result_path_irm is None:
200
- st.success("✅ Aucun résultat détecté ou limite gratuite atteinte.")
201
- else:
202
- st.image(result_path_irm, caption="IRM annotée", use_container_width=True)
203
-
204
- # ---------------- Upload IRM Stroke ----------------
205
- st.header("🧠 Détection AVC par IRM")
206
- stroke_file = st.file_uploader("Uploader une IRM pour Stroke", type=["jpg", "jpeg", "png"], key="stroke_uploader")
207
- if stroke_file and st.button("Analyser l'IRM Stroke", key="stroke_button"):
208
- stroke_image = Image.open(stroke_file)
209
- result_path_stroke = predict_image_stroke(stroke_image, conf=conf_threshold_stroke, show_labels=show_labels)
210
- if result_path_stroke is None:
211
- st.success("✅ Aucun résultat détecté ou limite gratuite atteinte.")
212
- else:
213
- st.image(result_path_stroke, caption="Stroke annotée", use_container_width=True)
214
-
215
-
216
- # Upload IRM 3D (cancer)
217
- st.header("🧠 Détection Tumeur (IRM 3D)")
218
- irm3d_files = st.file_uploader("Uploader 4 séquences (FLAIR, T1, T1CE, T2)", type=["nii", "nii.gz"], accept_multiple_files=True)
219
- if irm3d_files and st.button("Analyser IRM 3D"):
220
- if len(irm3d_files) != 4:
221
- st.error("⚠️ Merci d’uploader exactement 4 fichiers IRM (FLAIR, T1, T1CE, T2)")
222
- else:
223
- tmp_paths = []
224
- for f in irm3d_files:
225
- path = os.path.join(SAVE_DIR, f.name)
226
- with open(path, "wb") as out:
227
- out.write(f.read())
228
- tmp_paths.append(path)
229
- seg, report_text, (nii_path, report_path, mask_path) = irm_cancer_module.run(tmp_paths)
230
- st.subheader("📝 Rapport automatique")
231
- st.text(report_text)
232
- if mask_path and os.path.exists(mask_path):
233
- st.image(mask_path, caption="Segmentation annotée", use_container_width=True)
234
-
235
- # Disclaimer
236
- st.markdown(f"""
237
- ---
238
- 👨‍💻 **Badsi Djilali** — Ingénieur Deep Learning
239
- 🚀 Créateur de **Stroke_IA_Detection**
240
-
241
- ⚠️ Démo technique, pas un avis médical.
242
- © {datetime.now().year} — Badsi Djilali.
243
- """)
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import os
4
+
5
+ # File ka naam jahan data save hoga (CSV ki jagan ye auto-file banegi)
6
+ DB_FILE = "data_logs.csv"
7
+
8
+ # Function: Data ko bina upload kiye save karne ke liye
9
+ def save_data(scan_type, result):
10
+ new_data = pd.DataFrame([[pd.Timestamp.now(), scan_type, result]],
11
+ columns=["Time", "Type", "Status"])
12
+ if not os.path.isfile(DB_FILE):
13
+ new_data.to_csv(DB_FILE, index=False)
14
+ else:
15
+ new_data.to_csv(DB_FILE, mode='a', header=False, index=False)
16
+
17
+ st.title("🧠 Stroke-IA Detection Tool")
18
+
19
+ # Sidebar Menu for Mobile
20
+ menu = st.sidebar.selectbox("Menu", ["Detection", "Analytics (Auto-Data)"])
21
+
22
+ if menu == "Detection":
23
+ st.subheader("Upload Image/Video")
24
+ u_file = st.file_uploader("Choose file", type=['jpg', 'png', 'mp4'])
25
+
26
+ if u_file:
27
+ if st.button("Analyze & Save"):
28
+ # Yahan hum data auto-save kar rahe hain
29
+ save_data("Image/Video", "Analysis Done")
30
+ st.success("Result saved automatically to internal database!")
31
+ st.info("Ab aap Analytics menu mein ja kar ye data dekh sakte hain.")
32
+
33
+ elif menu == "Analytics (Auto-Data)":
34
+ st.subheader("📊 Auto-Generated Insights")
35
+ if os.path.exists(DB_FILE):
36
+ df = pd.read_csv(DB_FILE)
37
+ st.write("Ye data aapne pichle scans se generate kiya hai:")
38
+ st.dataframe(df)
39
+ # Chota graph mobile ke liye
40
+ st.line_chart(df.index)
41
+ else:
42
+ st.warning("Abhi tak koi data save nahi hua. Pehle ek scan karein!")