Update app.py
Browse files
app.py
CHANGED
@@ -56,9 +56,22 @@ css = """
|
|
56 |
font-size: 24px !important;
|
57 |
}
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
}
|
63 |
|
64 |
/* Style pour la div d'avertissement */
|
@@ -475,10 +488,12 @@ def quick_predict_ui(image_pil):
|
|
475 |
'<h2 class="output-class">Veuillez uploader une image.</h2>',
|
476 |
"", # output_text vide
|
477 |
None,
|
|
|
478 |
"❌ Erreur: Aucune image fournie."
|
479 |
)
|
480 |
|
481 |
try:
|
|
|
482 |
current_image = image_pil
|
483 |
all_preds = predict_single(image_pil)
|
484 |
current_predictions = all_preds
|
@@ -489,73 +504,45 @@ def quick_predict_ui(image_pil):
|
|
489 |
|
490 |
# Récupère la probabilité de "mel" (mélanome)
|
491 |
mel_idx = CLASS_NAMES.index("mel")
|
492 |
-
mel_prob = ensemble_probs[mel_idx] * 100
|
493 |
|
494 |
for top in description:
|
495 |
if top == top_class_name:
|
496 |
desc_top = description[top]
|
497 |
|
498 |
-
|
499 |
-
top_class_pourcent = round(max(confidences.values()), 2)
|
500 |
-
|
501 |
-
# Génère le HTML pour le diagnostic global
|
502 |
-
if global_diag == "Malin":
|
503 |
-
global_diag_html = f'''
|
504 |
-
<div style="float:left">
|
505 |
-
<img src="https://huggingface.co/spaces/ericjedha/skin_care/resolve/main/mel.webp" width="150">
|
506 |
-
</div>
|
507 |
-
<span style="font-size:20px">Diagnostic Global 💬</span>
|
508 |
-
<div class="highlight malin">{global_diag} : {top_class_pourcent} % ▪ {top_class_name.upper()} ▪</div>
|
509 |
-
'''
|
510 |
-
elif global_diag == "Bénin":
|
511 |
-
global_diag_html = f'''
|
512 |
-
<div style="float:left">
|
513 |
-
<img src="https://huggingface.co/spaces/ericjedha/skin_care/resolve/main/non-mel.webp" width="150">
|
514 |
-
</div>
|
515 |
-
<span style="font-size:20px">Diagnostic Global 💬</span>
|
516 |
-
<div class="highlight benin">{global_diag} : {top_class_pourcent} % ▪ {top_class_name.upper()} ▪</div>
|
517 |
-
'''
|
518 |
-
else:
|
519 |
-
global_diag_html = f'<div class="output-class">{global_diag} : {top_class_pourcent} % ▪ {top_class_name.upper()} ▪</div>'
|
520 |
|
521 |
# Génère le contenu pour output_text (explication + avertissement si nécessaire)
|
522 |
output_text_html = f'<div class="feedback-text">{desc_top}</div>'
|
523 |
|
524 |
# Ajoute un message d'avertissement si "mel" > 15%
|
525 |
if mel_prob > 15 and top_class_name != "mel":
|
526 |
-
warning_message = '''
|
527 |
<div class="warning-message">
|
528 |
⚠️ Le modèle a détecté un risque modéré de mélanome ({mel_prob:.1f}%).
|
529 |
Veuillez consulter votre médecin pour lever le doute.
|
530 |
</div>
|
531 |
-
'''
|
532 |
output_text_html += warning_message
|
533 |
|
534 |
-
#
|
535 |
-
df = pd.DataFrame.from_dict(confidences, orient='index', columns=['Probabilité']).reset_index().rename(columns={'index': 'Classe'})
|
536 |
-
df = df.sort_values(by='Probabilité', ascending=False)
|
537 |
-
df['Pourcentage'] = df['Probabilité'].apply(lambda x: f"{x:.1f}%")
|
538 |
-
fig = px.bar(df,
|
539 |
-
x="Classe",
|
540 |
-
y="Probabilité",
|
541 |
-
color="Probabilité",
|
542 |
-
color_continuous_scale=px.colors.sequential.Viridis,
|
543 |
-
title="Probabilités par classe",
|
544 |
-
text="Pourcentage")
|
545 |
-
text_positions = []
|
546 |
-
for val in df['Probabilité']:
|
547 |
-
if val <= 10:
|
548 |
-
text_positions.append("outside")
|
549 |
-
else:
|
550 |
-
text_positions.append("inside")
|
551 |
-
fig.update_traces(textposition=text_positions)
|
552 |
-
fig.update_layout(xaxis_title="", yaxis_title="Probabilité (%)", height=400)
|
553 |
-
|
554 |
-
return global_diag_html, output_text_html, fig, "✅ Analyse terminée. Prêt pour Grad-CAM."
|
555 |
|
556 |
-
|
557 |
-
|
|
|
|
|
|
|
|
|
|
|
558 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
559 |
|
560 |
|
561 |
def generate_gradcam_ui(progress=gr.Progress()):
|
@@ -621,17 +608,25 @@ with gr.Blocks(theme=theme, title="Analyse de lésions", css=css) as demo:
|
|
621 |
gr.Examples(examples=example_paths, inputs=input_image)
|
622 |
#ajout d'une ligne
|
623 |
gr.HTML(value="<details><p> <summary><b>Dataset utilisé ↓ ↑</b></summary> source : HAM10000, ce dataset HAM10000 a été créé par une équipe internationale dirigée par des chercheurs autrichiens, allemands et australiens.</details> <br><details><p> <summary><b>RGPD & Digital Act</b> ↓ ↑</summary> Ce dataset ne peut pas être utilisé pour des cas réels aujourd'hui notamment du fait qu'il ne comporte qu'essentiellement des peaux de populations européennes (allemands et autrichiens). Cette application ne collecte pas vos données personnes. <b>Les images uploadés ne sont pas stockées</b>. La politique de Cookies 🍪 est gérée par <a href='https://huggingface.co/privacy'>Hugging Face disponible ici</a>. </p>")
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
value="", # Contenu initial vide
|
629 |
-
elem_classes="feedback"
|
630 |
)
|
631 |
-
output_plot = gr.Plot(label="📈 Probabilités")
|
632 |
-
output_gradcam = gr.Image(label="🔍 Visualisation Grad-CAM")
|
633 |
-
output_status = gr.Textbox(label="Statut", interactive=False)
|
634 |
|
|
|
|
|
|
|
|
|
635 |
quick_btn.click(fn=quick_predict_ui, inputs=input_image, outputs=[output_label, output_text, output_plot, output_status])
|
636 |
gradcam_btn.click(fn=generate_gradcam_ui, inputs=[], outputs=[output_gradcam, output_status])
|
637 |
|
|
|
56 |
font-size: 24px !important;
|
57 |
}
|
58 |
|
59 |
+
#warning {background-color: #FFCCCB}
|
60 |
+
|
61 |
+
/* Conteneur pour l'explication */
|
62 |
+
.feedback-container {
|
63 |
+
background-color: #f9f9f9;
|
64 |
+
border-radius: 5px;
|
65 |
+
padding: 10px;
|
66 |
+
margin-bottom: 15px;
|
67 |
+
border: 1px solid #e0e0e0;
|
68 |
+
}
|
69 |
+
|
70 |
+
/* Style pour le texte d'explication */
|
71 |
+
.feedback-text {
|
72 |
+
font-size: 14px;
|
73 |
+
line-height: 1.5;
|
74 |
+
margin-bottom: 10px;
|
75 |
}
|
76 |
|
77 |
/* Style pour la div d'avertissement */
|
|
|
488 |
'<h2 class="output-class">Veuillez uploader une image.</h2>',
|
489 |
"", # output_text vide
|
490 |
None,
|
491 |
+
None,
|
492 |
"❌ Erreur: Aucune image fournie."
|
493 |
)
|
494 |
|
495 |
try:
|
496 |
+
# ... (ton code existant pour la prédiction)
|
497 |
current_image = image_pil
|
498 |
all_preds = predict_single(image_pil)
|
499 |
current_predictions = all_preds
|
|
|
504 |
|
505 |
# Récupère la probabilité de "mel" (mélanome)
|
506 |
mel_idx = CLASS_NAMES.index("mel")
|
507 |
+
mel_prob = ensemble_probs[mel_idx] * 100
|
508 |
|
509 |
for top in description:
|
510 |
if top == top_class_name:
|
511 |
desc_top = description[top]
|
512 |
|
513 |
+
# ... (ton code existant pour global_diag_html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
|
515 |
# Génère le contenu pour output_text (explication + avertissement si nécessaire)
|
516 |
output_text_html = f'<div class="feedback-text">{desc_top}</div>'
|
517 |
|
518 |
# Ajoute un message d'avertissement si "mel" > 15%
|
519 |
if mel_prob > 15 and top_class_name != "mel":
|
520 |
+
warning_message = f'''
|
521 |
<div class="warning-message">
|
522 |
⚠️ Le modèle a détecté un risque modéré de mélanome ({mel_prob:.1f}%).
|
523 |
Veuillez consulter votre médecin pour lever le doute.
|
524 |
</div>
|
525 |
+
'''
|
526 |
output_text_html += warning_message
|
527 |
|
528 |
+
# ... (ton code existant pour le graphique)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
529 |
|
530 |
+
return (
|
531 |
+
global_diag_html,
|
532 |
+
output_text_html,
|
533 |
+
fig,
|
534 |
+
None,
|
535 |
+
"✅ Analyse terminée. Prêt pour Grad-CAM."
|
536 |
+
)
|
537 |
|
538 |
+
except Exception as e:
|
539 |
+
return (
|
540 |
+
f'<h2 class="output-class">Erreur: {e}</h2>',
|
541 |
+
"",
|
542 |
+
None,
|
543 |
+
None,
|
544 |
+
"❌ Erreur lors de l'analyse."
|
545 |
+
)
|
546 |
|
547 |
|
548 |
def generate_gradcam_ui(progress=gr.Progress()):
|
|
|
608 |
gr.Examples(examples=example_paths, inputs=input_image)
|
609 |
#ajout d'une ligne
|
610 |
gr.HTML(value="<details><p> <summary><b>Dataset utilisé ↓ ↑</b></summary> source : HAM10000, ce dataset HAM10000 a été créé par une équipe internationale dirigée par des chercheurs autrichiens, allemands et australiens.</details> <br><details><p> <summary><b>RGPD & Digital Act</b> ↓ ↑</summary> Ce dataset ne peut pas être utilisé pour des cas réels aujourd'hui notamment du fait qu'il ne comporte qu'essentiellement des peaux de populations européennes (allemands et autrichiens). Cette application ne collecte pas vos données personnes. <b>Les images uploadés ne sont pas stockées</b>. La politique de Cookies 🍪 est gérée par <a href='https://huggingface.co/privacy'>Hugging Face disponible ici</a>. </p>")
|
611 |
+
with gr.Column(scale=2):
|
612 |
+
# Diagnostic global
|
613 |
+
gr.Markdown("### 📊 Diagnostic Global")
|
614 |
+
output_label = gr.HTML(
|
615 |
+
value='<h2 class="output-class">Veuillez uploader une image.</h2>',
|
616 |
+
elem_classes="diagnostic-global"
|
617 |
+
)
|
618 |
+
|
619 |
+
# Explication (avec un titre Markdown et un conteneur HTML)
|
620 |
+
gr.Markdown("### 💡 Explication")
|
621 |
+
output_text = gr.HTML(
|
622 |
value="", # Contenu initial vide
|
623 |
+
elem_classes="feedback-container"
|
624 |
)
|
|
|
|
|
|
|
625 |
|
626 |
+
# Graphique et Grad-CAM
|
627 |
+
output_plot = gr.Plot(label="📈 Probabilités")
|
628 |
+
output_gradcam = gr.Image(label="🔍 Visualisation Grad-CAM")
|
629 |
+
output_status = gr.Textbox(label="Statut", interactive=False)
|
630 |
quick_btn.click(fn=quick_predict_ui, inputs=input_image, outputs=[output_label, output_text, output_plot, output_status])
|
631 |
gradcam_btn.click(fn=generate_gradcam_ui, inputs=[], outputs=[output_gradcam, output_status])
|
632 |
|