File size: 11,342 Bytes
30f0946
8c18389
30f0946
 
 
 
a65b5eb
30f0946
 
 
 
 
04e9049
30f0946
a65b5eb
 
04e9049
a65b5eb
 
03f4248
30f0946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19307c3
 
30f0946
19307c3
30f0946
19307c3
 
 
 
 
 
 
 
 
30f0946
 
19307c3
 
 
 
 
 
 
 
 
 
 
30f0946
da2ce5b
 
 
 
 
 
 
 
 
 
 
 
 
 
30f0946
 
 
 
 
 
 
 
 
 
 
03f4248
 
 
 
 
 
 
 
 
30f0946
03f4248
30f0946
03f4248
 
 
30f0946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
import streamlit as st
#from streamlit_image_zoom import image_zoom  # Import de la bibliothèque pour le zoom
import base64
import os
from dotenv import load_dotenv
from anthropic import Anthropic
from openai import OpenAI
from PIL import Image, ImageOps
import tempfile

load_dotenv()

api_key = os.environ.get("OPENROUTERAI_API_KEY")

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=api_key, #os.environ.get("")
)
#client = Anthropic()
MODEL_NAME = "google/gemini-2.0-flash-lite-001" #"claude-3-opus-20240229"
# Définir le style global
st.set_page_config(
    page_title="Le Radiologue Virtuel",
    page_icon="🩺",
    layout="centered",
)

# CSS personnalisé pour styliser l'interface
st.markdown("""
    <style>
    body {
        background-color: #f4f4f9;
        color: #333333;
        font-family: 'Arial', sans-serif;
    }
    .stButton>button {
        background-color: #007bff;
        color: white;
        border-radius: 8px;
        padding: 0.5em 1.5em;
        font-size: 1em;
        border: none;
        transition: all 0.3s ease-in-out;
    }
    .stButton>button:hover {
        background-color: #0056b3;
        transform: scale(1.05);
    }
    .st-expander-header {
        font-weight: bold;
        font-size: 1.2em;
        color: #007bff;
    }
    .stMarkdown {
        font-size: 1.1em;
    }
    </style>
""", unsafe_allow_html=True)

sample_prompt = """
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. 
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.
**Instructions :**
1. Analysez uniquement les images liées au corps humain et aux problèmes de santé.
2. Rédigez votre réponse de manière structurée, détaillant :
   - Les anomalies identifiées (le cas échéant).
   - Les pathologies suspectées ou confirmées.
   - Les recommandations et étapes suivantes.
3. Si certains éléments ne sont pas clairs sur l'image, indiquez : *"Impossible de déterminer à partir de l'image fournie."*
4. Terminez toujours votre réponse par une mention : *"Consultez un médecin avant de prendre toute décision."*
"""

# Initialisation des variables d'état
if 'uploaded_file' not in st.session_state:
    st.session_state.uploaded_file = None
if 'result' not in st.session_state:
    st.session_state.result = None
if 'clinical_info' not in st.session_state:
    st.session_state.clinical_info = ""  # Pour stocker les renseignements cliniques


def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        binary_data = image_file.read()
        base_64_encoded_data = base64.b64encode(binary_data)
        base64_string = base_64_encoded_data.decode('utf-8')
        return base64_string


def call_groq_model_for_analysis(filename: str, clinical_info: str, sample_prompt=sample_prompt):
    # Récupérer l'extension du fichier pour définir le media_type
    file_extension = os.path.splitext(filename)[1].lower()  # Obtenir l'extension en minuscule
    if file_extension == ".jpg" or file_extension == ".jpeg":
        media_type = "image/jpeg"
    elif file_extension == ".png":
        media_type = "image/png"
    else:
        raise ValueError("Format de fichier non pris en charge.")
    base64_image = encode_image(filename)
    # Ajouter les renseignements cliniques au prompt
    full_prompt = sample_prompt + f"\n\n**Renseignements cliniques du patient :** {clinical_info}\n"

    
    message_list=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": full_prompt,
                },
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:{media_type};base64,{base64_image}"},
                },
            ],
        }
    ]
    
    
    #message_list = [
    #    {
    #        "role": 'user',
    #        "content": [
    #            {"type": "image", "source": {"type": "base64", "media_type": media_type, "data": base64_image}},
    #            {"type": "text", "text": full_prompt}
    #        ]
    #    }
    #]

    #response = client.messages.create(
    #model=MODEL_NAME,
    #max_tokens=2048,
    #messages=message_list
#)

    #print(response.content[0].text)
    #return response.content[0].text
    response = client.chat.completions.create(
        model=MODEL_NAME,
        max_tokens=2048,
        messages=message_list
    )
    return response.choices[0].message.content


def chat_eli(query):
    eli5_prompt = "Tu dois expliquer l'information ci-dessous à un enfant de cinq ans. \n" + query
    messages = [
        {
            "role": "user",
            "content": eli5_prompt
        }
    ]

    #response = client.messages.create(
    #model="claude-3-5-sonnet-20241022",
    #max_tokens=1024,
    #messages=messages
#)
    #return response.content[0].text
    
    completion = client.chat.completions.create(
    model="google/gemini-2.0-flash-lite-001", 
    messages=messages
    )

    return completion.choices[0].message.content

    


# Titre de l'application
st.title("🩺 **Le Radiologue Virtuel**")
st.subheader("Une IA avancée pour l'analyse des images médicales")

with st.expander("📖 A-Propos de cette Application"):
    st.markdown("""
        **Bienvenue sur LE RADIOLOGUE VIRTUEL**, votre assistant intelligent conçu pour fournir une analyse approfondie et précise des images médicales.  

        ### Fonctionnalités principales :
        - **Analyse d'images médicales** : Téléchargez des clichés d'échographie, de radiographie, d'IRM ou de TDM, et laissez l'IA détecter les anomalies et fournir des recommandations détaillées.  
        - **Explications simplifiées** : Grâce à la fonction ELI5, comprenez les résultats complexes sous une forme adaptée à un public non expert.  
        - **Traitement d'image avancé** : Explorez l'image téléchargée avec des outils comme l'inversion pour une visualisation plus claire.  

        ### Cas d'utilisation :
        - **Éducation médicale** : Destiné aux étudiants en radiologie, cet outil aide à se familiariser avec l'interprétation des images diagnostiques.  
        - **Support clinique** : Bien que non conçu pour remplacer un professionnel de santé, cet assistant peut fournir des indications utiles pour guider les analyses.  
        - **Recherche et apprentissage** : Une plateforme idéale pour expérimenter et apprendre l'impact de l'IA dans le domaine médical.  

        ### Technologie utilisée :
        - **Modèle d'IA puissant** : L'IA utilise la technologie avancée de Llama 3.2 90B Vision, spécialisée dans l'analyse d'images complexes.  
        - **Interaction intuitive** : Développé avec Python et Streamlit pour une interface simple et conviviale.  
        - **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.

        **⚠️ Avertissement** :
        - Cet assistant n'est pas un outil médical certifié et ne remplace en aucun cas l'avis d'un médecin ou d'un spécialiste. Il est destiné à des fins éducatives et de support. Consultez toujours un professionnel de santé pour un diagnostic ou une décision médicale.  
    """)

# Champ d'entrée pour les renseignements cliniques
clinical_info = st.text_area(
    "Renseignements cliniques du patient (facultatif)",
    placeholder="Exemple : Patient présentant une douleur thoracique depuis 3 jours."
)

# Stocker les renseignements cliniques dans la session
st.session_state['clinical_info'] = clinical_info

# Téléchargement de l'image
st.markdown("### 📂 Téléchargez une image médicale")
uploaded_file = st.file_uploader("Formats acceptés : JPG, JPEG, PNG", type=["jpg", "jpeg", "png"])

# Gestion temporaire des fichiers
if uploaded_file is not None:
    with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded_file.name)[1]) as tmp_file:
        tmp_file.write(uploaded_file.getvalue())
        st.session_state['filename'] = tmp_file.name

    st.image(uploaded_file, caption='Image Téléchargée')

    # Charger l'image avec PIL
    image = Image.open(uploaded_file)

    # Ajouter un bouton pour afficher l'image en négatif
    st.markdown("### 🔍 Explorez l'image")
    col1, col2, col3 = st.columns([1, 2, 1])  # colonnes avec différentes proportions
    col1.write("")  # Espace dans la première colonne
    col3.write("")  # Espace dans la troisième colonne
    col1.write("")  # Espace dans la première colonne
    col3.write("")  # Espace dans la troisième colonne
    if st.button("Afficher l'image en négatif"):
        # Créer une version négative de l'image
        negative_image = ImageOps.invert(image.convert("RGB"))  # Convertir en RGB avant inversion

        # Afficher l'image en négatif
        st.subheader("Image en négatif :")
        st.image(negative_image, caption="Image en négatif")
    col1, col2, col3 = st.columns([1, 2, 1])  # colonnes avec différentes proportions
    col1.write("")  # Espace dans la première colonne
    col3.write("")  # Espace dans la troisième colonne
    col1.write("")  # Espace dans la première colonne
    col3.write("")  # Espace dans la troisième colonne

    # Bouton pour analyser l'image
    if st.button("Analyse l'Image"):
        if 'filename' in st.session_state and os.path.exists(st.session_state['filename']):
            with st.spinner("Analyse en cours... Veuillez patienter."):
                st.session_state['result'] = call_groq_model_for_analysis(
                    st.session_state['filename'],
                    st.session_state['clinical_info']
                )
                st.success("Analyse terminée avec succès !")
                st.markdown(st.session_state['result'], unsafe_allow_html=True)
                os.unlink(st.session_state['filename'])  # Supprimer le fichier temporaire après le traitement

    # ELI5 Explanation
    # Explication simplifiée
    st.markdown("### 🤓 Explication Simplifiée")
    if 'result' in st.session_state and st.session_state['result']:
        st.info("Ci-dessous, vous avez une option pour ELI5 afin de comprendre en termes simples.")
        if st.radio("ELI5 - Explique-moi comme si j'avais 5 ans", ('NON', 'OUI')) == 'OUI':
            st.markdown("_Voici une explication simplifiée pour les non-initiés._")
            simplified_explanation = chat_eli(st.session_state['result'])
            st.markdown(simplified_explanation, unsafe_allow_html=True)

# Pied de page
st.markdown("""
    <hr>
    <footer style="text-align: center; font-size: 0.9em;">
        © 2024 - Le Radiologue Virtuel | Propulsé par M. ADJOUMANI
    </footer>
""", unsafe_allow_html=True)