Spaces:
Running
Running
Translation to English
Browse files
app.py
CHANGED
@@ -15,7 +15,7 @@ load_dotenv()
|
|
15 |
api_key = os.environ.get("XAI_API_KEY")
|
16 |
|
17 |
if not api_key:
|
18 |
-
raise ValueError("
|
19 |
|
20 |
client = OpenAI(
|
21 |
api_key=api_key,
|
@@ -25,7 +25,7 @@ client = OpenAI(
|
|
25 |
#MODEL_NAME ="claude-3-opus-20240229"
|
26 |
# Définir le style global
|
27 |
st.set_page_config(
|
28 |
-
page_title="
|
29 |
page_icon="🩺",
|
30 |
layout="centered",
|
31 |
)
|
@@ -66,13 +66,13 @@ sample_prompt = """
|
|
66 |
Vous êtes un professionnel de santé, expert dans l'analyse des images médicales (échographie, radiographie standard, TDM, IRM, ...), travaillant pour un hôpital de renom. Votre tâche consiste à examiner des images médicales afin d'identifier les anomalies, maladies ou problèmes de santé éventuels. Vous devez fournir des résultats détaillés, incluant toutes vos observations, les prochaines étapes, ainsi que des recommandations.
|
67 |
Votre analyse reste dans le cadre éducatif d'étudiants en radiologie médicale et ne sera en aucun cas publique. L'objectif est d'initier ces étudiants à l'interpretation des clichés radiologique.
|
68 |
**Instructions :**
|
69 |
-
1.
|
70 |
-
2.
|
71 |
-
-
|
72 |
-
-
|
73 |
-
-
|
74 |
-
3.
|
75 |
-
4.
|
76 |
"""
|
77 |
|
78 |
# Initialisation des variables d'état
|
@@ -98,10 +98,10 @@ def call_groq_model_for_analysis(filename: str, clinical_info: str, sample_promp
|
|
98 |
elif file_extension == ".png":
|
99 |
media_type = "image/png"
|
100 |
else:
|
101 |
-
raise ValueError("
|
102 |
base64_image = encode_image(filename)
|
103 |
# Ajouter les renseignements cliniques au prompt
|
104 |
-
full_prompt = sample_prompt + f"\n\n**
|
105 |
|
106 |
|
107 |
|
@@ -132,7 +132,7 @@ def call_groq_model_for_analysis(filename: str, clinical_info: str, sample_promp
|
|
132 |
|
133 |
|
134 |
def chat_eli(query):
|
135 |
-
eli5_prompt = "
|
136 |
messages = [
|
137 |
{
|
138 |
"role": "user",
|
@@ -155,44 +155,43 @@ def chat_eli(query):
|
|
155 |
|
156 |
|
157 |
# Titre de l'application
|
158 |
-
st.title("🩺 **
|
159 |
-
st.subheader("
|
160 |
|
161 |
-
with st.expander("📖
|
162 |
st.markdown("""
|
163 |
-
**
|
164 |
|
165 |
-
###
|
166 |
-
- **
|
167 |
-
- **
|
168 |
-
- **
|
169 |
|
170 |
-
###
|
171 |
-
-
|
172 |
-
- **
|
173 |
-
- **
|
174 |
|
175 |
-
###
|
176 |
-
- **
|
177 |
-
- **Interaction
|
178 |
-
- **Sécurité et confidentialité** : Toutes les analyses sont effectuées localement ou sur des serveurs sécurisés, garantissant la confidentialité des données médicales.
|
179 |
|
180 |
-
**⚠️
|
181 |
-
-
|
182 |
""")
|
183 |
|
184 |
# Champ d'entrée pour les renseignements cliniques
|
185 |
clinical_info = st.text_area(
|
186 |
-
"
|
187 |
-
placeholder="
|
188 |
)
|
189 |
|
190 |
# Stocker les renseignements cliniques dans la session
|
191 |
st.session_state['clinical_info'] = clinical_info
|
192 |
|
193 |
# Téléchargement de l'image
|
194 |
-
st.markdown("### 📂
|
195 |
-
uploaded_file = st.file_uploader("
|
196 |
|
197 |
# Gestion temporaire des fichiers
|
198 |
if uploaded_file is not None:
|
@@ -200,25 +199,25 @@ if uploaded_file is not None:
|
|
200 |
tmp_file.write(uploaded_file.getvalue())
|
201 |
st.session_state['filename'] = tmp_file.name
|
202 |
|
203 |
-
st.image(uploaded_file, caption='
|
204 |
|
205 |
# Charger l'image avec PIL
|
206 |
image = Image.open(uploaded_file)
|
207 |
|
208 |
# Ajouter un bouton pour afficher l'image en négatif
|
209 |
-
st.markdown("### 🔍
|
210 |
col1, col2, col3 = st.columns([1, 2, 1]) # colonnes avec différentes proportions
|
211 |
col1.write("") # Espace dans la première colonne
|
212 |
col3.write("") # Espace dans la troisième colonne
|
213 |
col1.write("") # Espace dans la première colonne
|
214 |
col3.write("") # Espace dans la troisième colonne
|
215 |
-
if st.button("
|
216 |
# Créer une version négative de l'image
|
217 |
negative_image = ImageOps.invert(image.convert("RGB")) # Convertir en RGB avant inversion
|
218 |
|
219 |
# Afficher l'image en négatif
|
220 |
-
st.subheader("
|
221 |
-
st.image(negative_image, caption="
|
222 |
col1, col2, col3 = st.columns([1, 2, 1]) # colonnes avec différentes proportions
|
223 |
col1.write("") # Espace dans la première colonne
|
224 |
col3.write("") # Espace dans la troisième colonne
|
@@ -226,16 +225,16 @@ if uploaded_file is not None:
|
|
226 |
col3.write("") # Espace dans la troisième colonne
|
227 |
|
228 |
# Bouton pour analyser l'image
|
229 |
-
if st.button("
|
230 |
if 'filename' in st.session_state and os.path.exists(st.session_state['filename']):
|
231 |
-
with st.spinner("
|
232 |
# Appel au modèle Groq pour l'analyse
|
233 |
st.session_state['result'] = call_groq_model_for_analysis(
|
234 |
st.session_state['filename'],
|
235 |
st.session_state['clinical_info']
|
236 |
)
|
237 |
|
238 |
-
st.success("
|
239 |
|
240 |
# Effet de streaming pour afficher le résultat
|
241 |
result_text = st.session_state['result']
|
@@ -249,7 +248,7 @@ if uploaded_file is not None:
|
|
249 |
time.sleep(0.05) # Simuler le délai
|
250 |
container.markdown(streamed_text, unsafe_allow_html=True)
|
251 |
else:
|
252 |
-
st.error("
|
253 |
|
254 |
# Supprimer le fichier temporaire après le traitement
|
255 |
os.unlink(st.session_state['filename'])
|
@@ -257,11 +256,11 @@ if uploaded_file is not None:
|
|
257 |
|
258 |
# ELI5 Explanation
|
259 |
# Explication simplifiée
|
260 |
-
st.markdown("### 🤓
|
261 |
if 'result' in st.session_state and st.session_state['result']:
|
262 |
-
st.info("
|
263 |
-
if st.radio("ELI5 -
|
264 |
-
st.markdown("
|
265 |
simplified_explanation = chat_eli(st.session_state['result'])
|
266 |
st.markdown(simplified_explanation, unsafe_allow_html=True)
|
267 |
|
@@ -269,6 +268,6 @@ if uploaded_file is not None:
|
|
269 |
st.markdown("""
|
270 |
<hr>
|
271 |
<footer style="text-align: center; font-size: 0.9em;">
|
272 |
-
© 2025 -
|
273 |
</footer>
|
274 |
""", unsafe_allow_html=True)
|
|
|
15 |
api_key = os.environ.get("XAI_API_KEY")
|
16 |
|
17 |
if not api_key:
|
18 |
+
raise ValueError("The XAI API key is not defined in the secrets.")
|
19 |
|
20 |
client = OpenAI(
|
21 |
api_key=api_key,
|
|
|
25 |
#MODEL_NAME ="claude-3-opus-20240229"
|
26 |
# Définir le style global
|
27 |
st.set_page_config(
|
28 |
+
page_title="The Virtual Radiologist",
|
29 |
page_icon="🩺",
|
30 |
layout="centered",
|
31 |
)
|
|
|
66 |
Vous êtes un professionnel de santé, expert dans l'analyse des images médicales (échographie, radiographie standard, TDM, IRM, ...), travaillant pour un hôpital de renom. Votre tâche consiste à examiner des images médicales afin d'identifier les anomalies, maladies ou problèmes de santé éventuels. Vous devez fournir des résultats détaillés, incluant toutes vos observations, les prochaines étapes, ainsi que des recommandations.
|
67 |
Votre analyse reste dans le cadre éducatif d'étudiants en radiologie médicale et ne sera en aucun cas publique. L'objectif est d'initier ces étudiants à l'interpretation des clichés radiologique.
|
68 |
**Instructions :**
|
69 |
+
1. I will only analyze images related to the human body and health issues.
|
70 |
+
2. My responses will be structured and detailed, covering:
|
71 |
+
- Identified anomalies (if any).
|
72 |
+
- Suspected or confirmed pathologies.
|
73 |
+
- Recommendations and next steps.
|
74 |
+
3. If certain elements are unclear in the image, I will state: "Impossible to determine from the provided image. Consult a doctor before making any decisions."*
|
75 |
+
4. I will always conclude my response with : *"Consult a doctor before making any decisions."*
|
76 |
"""
|
77 |
|
78 |
# Initialisation des variables d'état
|
|
|
98 |
elif file_extension == ".png":
|
99 |
media_type = "image/png"
|
100 |
else:
|
101 |
+
raise ValueError("Unsupported file format.")
|
102 |
base64_image = encode_image(filename)
|
103 |
# Ajouter les renseignements cliniques au prompt
|
104 |
+
full_prompt = sample_prompt + f"\n\n**Patient's clinical information:** {clinical_info}\n"
|
105 |
|
106 |
|
107 |
|
|
|
132 |
|
133 |
|
134 |
def chat_eli(query):
|
135 |
+
eli5_prompt = "You need to explain the information below to a five-year-old. \n" + query
|
136 |
messages = [
|
137 |
{
|
138 |
"role": "user",
|
|
|
155 |
|
156 |
|
157 |
# Titre de l'application
|
158 |
+
st.title("🩺 **The Virtual Radiologist**")
|
159 |
+
st.subheader("An advanced AI for medical image analysis")
|
160 |
|
161 |
+
with st.expander("📖 About This Application"):
|
162 |
st.markdown("""
|
163 |
+
**Welcome to the Virtual Radiologist**, your intelligent assistant designed to provide in-depth and accurate analysis of medical images..
|
164 |
|
165 |
+
### Main Features :
|
166 |
+
- **Medical Image Analysis** : Upload ultrasound, X-ray, MRI, or CT scan images and let the AI detect anomalies and provide detailed recommendations.
|
167 |
+
- **Simplified Explanations** : With the ELI5 feature, understand complex results in a format tailored for a non-expert audience.
|
168 |
+
- **Advanced Image Treatment** : Explore the uploaded image with tools like inversion for clearer visualization.
|
169 |
|
170 |
+
### Use Cases :
|
171 |
+
- **Medical education** : Intended for radiology students, this tool helps to become familiar with the interpretation of diagnostic images.
|
172 |
+
- **Clinical support** : While not designed to replace a healthcare professional, this assistant can provide helpful insights to guide analyses.
|
173 |
+
- **Research and learning** : An ideal platform for experimenting with and learning about the impact of AI in the medical field.
|
174 |
|
175 |
+
### Technology used :
|
176 |
+
- **Powerful AI model** : The AI uses advanced Llama 3.2 90B Vision technology, specialized in analyzing complex images.
|
177 |
+
- **Intuitive Interaction ** : Developed with Python and Streamlit for a simple and user-friendly interface.
|
|
|
178 |
|
179 |
+
**⚠️ Caution** :
|
180 |
+
- This assistant is not a certified medical tool and does not replace the advice of a doctor or specialist. It is intended for educational and support purposes. Always consult a healthcare professional for diagnosis or medical decisions.
|
181 |
""")
|
182 |
|
183 |
# Champ d'entrée pour les renseignements cliniques
|
184 |
clinical_info = st.text_area(
|
185 |
+
"Patient clinical information (optional))",
|
186 |
+
placeholder="Example: Patient presenting with chest pain for 3 days."
|
187 |
)
|
188 |
|
189 |
# Stocker les renseignements cliniques dans la session
|
190 |
st.session_state['clinical_info'] = clinical_info
|
191 |
|
192 |
# Téléchargement de l'image
|
193 |
+
st.markdown("### 📂 Upload a medical image")
|
194 |
+
uploaded_file = st.file_uploader("Accepted formats : JPG, JPEG, PNG", type=["jpg", "jpeg", "png"])
|
195 |
|
196 |
# Gestion temporaire des fichiers
|
197 |
if uploaded_file is not None:
|
|
|
199 |
tmp_file.write(uploaded_file.getvalue())
|
200 |
st.session_state['filename'] = tmp_file.name
|
201 |
|
202 |
+
st.image(uploaded_file, caption='Uploaded File')
|
203 |
|
204 |
# Charger l'image avec PIL
|
205 |
image = Image.open(uploaded_file)
|
206 |
|
207 |
# Ajouter un bouton pour afficher l'image en négatif
|
208 |
+
st.markdown("### 🔍 Explore the image")
|
209 |
col1, col2, col3 = st.columns([1, 2, 1]) # colonnes avec différentes proportions
|
210 |
col1.write("") # Espace dans la première colonne
|
211 |
col3.write("") # Espace dans la troisième colonne
|
212 |
col1.write("") # Espace dans la première colonne
|
213 |
col3.write("") # Espace dans la troisième colonne
|
214 |
+
if st.button("Negative view"):
|
215 |
# Créer une version négative de l'image
|
216 |
negative_image = ImageOps.invert(image.convert("RGB")) # Convertir en RGB avant inversion
|
217 |
|
218 |
# Afficher l'image en négatif
|
219 |
+
st.subheader("Negative view :")
|
220 |
+
st.image(negative_image, caption="Negative view")
|
221 |
col1, col2, col3 = st.columns([1, 2, 1]) # colonnes avec différentes proportions
|
222 |
col1.write("") # Espace dans la première colonne
|
223 |
col3.write("") # Espace dans la troisième colonne
|
|
|
225 |
col3.write("") # Espace dans la troisième colonne
|
226 |
|
227 |
# Bouton pour analyser l'image
|
228 |
+
if st.button("Image Analysis"):
|
229 |
if 'filename' in st.session_state and os.path.exists(st.session_state['filename']):
|
230 |
+
with st.spinner("Analysis in progress... Please wait."):
|
231 |
# Appel au modèle Groq pour l'analyse
|
232 |
st.session_state['result'] = call_groq_model_for_analysis(
|
233 |
st.session_state['filename'],
|
234 |
st.session_state['clinical_info']
|
235 |
)
|
236 |
|
237 |
+
st.success("Analysis completed successfully!")
|
238 |
|
239 |
# Effet de streaming pour afficher le résultat
|
240 |
result_text = st.session_state['result']
|
|
|
248 |
time.sleep(0.05) # Simuler le délai
|
249 |
container.markdown(streamed_text, unsafe_allow_html=True)
|
250 |
else:
|
251 |
+
st.error("Error creating display.")
|
252 |
|
253 |
# Supprimer le fichier temporaire après le traitement
|
254 |
os.unlink(st.session_state['filename'])
|
|
|
256 |
|
257 |
# ELI5 Explanation
|
258 |
# Explication simplifiée
|
259 |
+
st.markdown("### 🤓 Simplified Explanation")
|
260 |
if 'result' in st.session_state and st.session_state['result']:
|
261 |
+
st.info("Below, there's an ELI5 option to help you understand in simple terms.")
|
262 |
+
if st.radio("ELI5 - Explain it to me like I'm 5", ('NO', 'YES')) == 'YES':
|
263 |
+
st.markdown("_Here is a simplified explanation for non-experts._")
|
264 |
simplified_explanation = chat_eli(st.session_state['result'])
|
265 |
st.markdown(simplified_explanation, unsafe_allow_html=True)
|
266 |
|
|
|
268 |
st.markdown("""
|
269 |
<hr>
|
270 |
<footer style="text-align: center; font-size: 0.9em;">
|
271 |
+
© 2025 - The Virtual Radiologist | By M. ADJOUMANI
|
272 |
</footer>
|
273 |
""", unsafe_allow_html=True)
|