Update app.py
Browse files
app.py
CHANGED
@@ -100,6 +100,31 @@ os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
|
|
100 |
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
101 |
tf.config.set_visible_devices([], 'GPU')
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
# ---- Configuration ----
|
104 |
CLASS_NAMES = ['akiec', 'bcc', 'bkl', 'df', 'nv', 'vasc', 'mel']
|
105 |
label_to_index = {name: i for i, name in enumerate(CLASS_NAMES)}
|
@@ -481,6 +506,111 @@ def make_gradcam(image_pil, model, last_conv_layer_name, class_index, progress=N
|
|
481 |
_update_progress(progress, 100, "❌ Erreur")
|
482 |
return np.array(image_pil)
|
483 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
# ---- GESTION ASYNCHRONE / ÉTAT ----
|
485 |
current_image = None
|
486 |
current_predictions = None
|
@@ -507,7 +637,8 @@ def quick_predict_ui(image_pil):
|
|
507 |
"", # output_text vide
|
508 |
gr.update(value="", visible=False), # output_warning masqué
|
509 |
empty_fig, # Figure vide au lieu de None
|
510 |
-
"❌ Erreur: Aucune image fournie."
|
|
|
511 |
)
|
512 |
|
513 |
try:
|
@@ -522,6 +653,10 @@ def quick_predict_ui(image_pil):
|
|
522 |
# Probabilité de mélanome
|
523 |
mel_idx = CLASS_NAMES.index("mel")
|
524 |
mel_prob = ensemble_probs[mel_idx] * 100
|
|
|
|
|
|
|
|
|
525 |
|
526 |
# Description
|
527 |
desc_top = description.get(top_class_name, "")
|
@@ -568,6 +703,20 @@ def quick_predict_ui(image_pil):
|
|
568 |
'''
|
569 |
warning_visible = True
|
570 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
# Création du graphique Plotly
|
572 |
probabilities = [round(ensemble_probs[i] * 100, 2) for i in range(len(CLASS_NAMES))]
|
573 |
|
@@ -578,34 +727,33 @@ def quick_predict_ui(image_pil):
|
|
578 |
go.Bar(
|
579 |
x=CLASS_NAMES,
|
580 |
y=probabilities,
|
581 |
-
text=[f'{p:.2f}%' for p in probabilities],
|
582 |
-
textposition='outside',
|
583 |
marker_color=colors,
|
584 |
hovertemplate='<b>%{x}</b><br>Probabilité: %{y:.2f}%<extra></extra>'
|
585 |
)
|
586 |
])
|
587 |
|
588 |
fig.update_layout(
|
589 |
-
#title="Probabilités par classe",
|
590 |
xaxis_title="Classes",
|
591 |
yaxis_title="Probabilité (%)",
|
592 |
-
yaxis=dict(range=[0, max(probabilities) * 1.15]),
|
593 |
height=450,
|
594 |
template="plotly_white",
|
595 |
showlegend=False,
|
596 |
font=dict(size=12),
|
597 |
-
margin=dict(l=50, r=50, t=70, b=100)
|
598 |
)
|
599 |
|
600 |
-
# Rotation des labels x pour une meilleure lisibilité
|
601 |
fig.update_xaxes(tickangle=45)
|
602 |
|
603 |
return (
|
604 |
global_diag_html,
|
605 |
output_text_html,
|
606 |
gr.update(value=warning_html, visible=warning_visible),
|
607 |
-
fig,
|
608 |
-
"✅ Analyse terminée."
|
|
|
609 |
)
|
610 |
|
611 |
except Exception as e:
|
@@ -618,6 +766,13 @@ def quick_predict_ui(image_pil):
|
|
618 |
showlegend=False
|
619 |
)
|
620 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
return (
|
622 |
f'<div class="diagnostic-global"><h2>Erreur: {str(e)}</h2></div>',
|
623 |
"",
|
@@ -626,10 +781,11 @@ def quick_predict_ui(image_pil):
|
|
626 |
❌ Une erreur est survenue : {str(e)}
|
627 |
</div>
|
628 |
''', visible=True),
|
629 |
-
error_fig,
|
630 |
-
f"❌ Erreur: {str(e)}"
|
|
|
631 |
)
|
632 |
-
|
633 |
def generate_gradcam_ui(progress=gr.Progress()):
|
634 |
global current_image, current_predictions
|
635 |
if current_image is None or current_predictions is None:
|
@@ -732,6 +888,8 @@ with gr.Blocks(theme=theme, title="Analyse de lésions", css=css) as demo:
|
|
732 |
|
733 |
# Configuration correcte du BarPlot
|
734 |
output_plot = gr.Plot(label="Probabilités par classe")
|
|
|
|
|
735 |
|
736 |
gr.Markdown(f"Ensemble de modèles utilisés : {', '.join(models_status) if models_status else 'AUCUN'}")
|
737 |
gr.HTML(value="""
|
@@ -747,7 +905,7 @@ with gr.Blocks(theme=theme, title="Analyse de lésions", css=css) as demo:
|
|
747 |
quick_btn.click(
|
748 |
fn=quick_predict_ui,
|
749 |
inputs=input_image,
|
750 |
-
outputs=[output_label, output_text, output_warning, output_plot, output_status]
|
751 |
)
|
752 |
|
753 |
gradcam_btn.click(
|
|
|
100 |
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
101 |
tf.config.set_visible_devices([], 'GPU')
|
102 |
|
103 |
+
|
104 |
+
# =============================================================================
|
105 |
+
# 1. IMPORTS ET CHARGEMENT DU MODÈLE (à ajouter en début de fichier)
|
106 |
+
# =============================================================================
|
107 |
+
|
108 |
+
from transformers import pipeline
|
109 |
+
import torch
|
110 |
+
|
111 |
+
# Chargement du modèle Microsoft BiomedBERT
|
112 |
+
med_nlp = None
|
113 |
+
try:
|
114 |
+
print("📥 Chargement du modèle médical Microsoft BiomedBERT...")
|
115 |
+
med_nlp = pipeline(
|
116 |
+
"text-classification",
|
117 |
+
model="microsoft/BiomedNLP-BiomedBERT-base-uncased-abstract",
|
118 |
+
framework="pt",
|
119 |
+
device=0 if torch.cuda.is_available() else -1 # GPU si disponible
|
120 |
+
)
|
121 |
+
print("✅ Microsoft BiomedBERT chargé avec succès")
|
122 |
+
except Exception as e:
|
123 |
+
print(f"❌ Erreur lors du chargement de Microsoft BiomedBERT: {e}")
|
124 |
+
med_nlp = None
|
125 |
+
|
126 |
+
|
127 |
+
|
128 |
# ---- Configuration ----
|
129 |
CLASS_NAMES = ['akiec', 'bcc', 'bkl', 'df', 'nv', 'vasc', 'mel']
|
130 |
label_to_index = {name: i for i, name in enumerate(CLASS_NAMES)}
|
|
|
506 |
_update_progress(progress, 100, "❌ Erreur")
|
507 |
return np.array(image_pil)
|
508 |
|
509 |
+
# =============================================================================
|
510 |
+
# 2. FONCTION D'ANALYSE MÉDICALE (à ajouter après vos fonctions existantes)
|
511 |
+
# =============================================================================
|
512 |
+
|
513 |
+
def get_medical_analysis(top_class_name, confidence, mel_prob):
|
514 |
+
"""
|
515 |
+
Analyse médicale utilisant Microsoft BiomedBERT
|
516 |
+
"""
|
517 |
+
global med_nlp
|
518 |
+
|
519 |
+
if med_nlp is None:
|
520 |
+
return {
|
521 |
+
"status": "error",
|
522 |
+
"analysis": "Modèle médical non disponible",
|
523 |
+
"recommendation": "Consultez un dermatologue pour un diagnostic professionnel."
|
524 |
+
}
|
525 |
+
|
526 |
+
try:
|
527 |
+
# Construction du texte médical basé sur la prédiction
|
528 |
+
medical_context = f"""
|
529 |
+
Dermatology diagnosis: {top_class_name} detected with {confidence:.1f}% confidence.
|
530 |
+
Clinical findings suggest {CLASS_NAMES_FULL.get(top_class_name, top_class_name)}.
|
531 |
+
Melanoma probability: {mel_prob:.1f}%.
|
532 |
+
Patient requires medical evaluation for skin lesion assessment.
|
533 |
+
"""
|
534 |
+
|
535 |
+
# Analyse avec BiomedBERT
|
536 |
+
result = med_nlp(medical_context)
|
537 |
+
|
538 |
+
# Interprétation des résultats
|
539 |
+
if result and len(result) > 0:
|
540 |
+
score = result[0].get('score', 0)
|
541 |
+
label = result[0].get('label', 'UNKNOWN')
|
542 |
+
|
543 |
+
# Génération de recommandations basées sur l'analyse
|
544 |
+
if score > 0.7:
|
545 |
+
recommendation_level = "urgent"
|
546 |
+
elif score > 0.5:
|
547 |
+
recommendation_level = "modéré"
|
548 |
+
else:
|
549 |
+
recommendation_level = "surveillance"
|
550 |
+
|
551 |
+
return {
|
552 |
+
"status": "success",
|
553 |
+
"biomed_score": score,
|
554 |
+
"biomed_label": label,
|
555 |
+
"recommendation_level": recommendation_level,
|
556 |
+
"analysis": f"Analyse BiomedBERT: {label} (score: {score:.3f})",
|
557 |
+
"recommendation": get_medical_recommendation(top_class_name, mel_prob, recommendation_level)
|
558 |
+
}
|
559 |
+
else:
|
560 |
+
return {
|
561 |
+
"status": "error",
|
562 |
+
"analysis": "Analyse BiomedBERT échouée",
|
563 |
+
"recommendation": "Consultez un dermatologue pour un diagnostic professionnel."
|
564 |
+
}
|
565 |
+
|
566 |
+
except Exception as e:
|
567 |
+
print(f"Erreur analyse BiomedBERT: {e}")
|
568 |
+
return {
|
569 |
+
"status": "error",
|
570 |
+
"analysis": f"Erreur technique: {str(e)}",
|
571 |
+
"recommendation": "Consultez un dermatologue pour un diagnostic professionnel."
|
572 |
+
}
|
573 |
+
|
574 |
+
def get_medical_recommendation(class_name, mel_prob, level):
|
575 |
+
"""
|
576 |
+
Génère des recommandations médicales personnalisées
|
577 |
+
"""
|
578 |
+
base_recommendations = {
|
579 |
+
"mel": "🚨 URGENT: Consultation immédiate chez un dermatologue recommandée.",
|
580 |
+
"bcc": "⚠️ Consultation dermatologique recommandée sous 2-4 semaines.",
|
581 |
+
"akiec": "📋 Surveillance dermatologique régulière conseillée.",
|
582 |
+
"bkl": "✅ Lésion généralement bénigne, surveillance de routine.",
|
583 |
+
"df": "📋 Suivi dermatologique pour confirmation diagnostique.",
|
584 |
+
"nv": "✅ Grain de beauté typique, surveillance habituelle.",
|
585 |
+
"vasc": "📋 Évaluation dermatologique pour suivi approprié."
|
586 |
+
}
|
587 |
+
|
588 |
+
base_rec = base_recommendations.get(class_name, "📋 Consultation dermatologique recommandée.")
|
589 |
+
|
590 |
+
if mel_prob > 10:
|
591 |
+
return f"{base_rec} ⚠️ Attention: Risque mélanome détecté ({mel_prob:.1f}%)."
|
592 |
+
elif level == "urgent":
|
593 |
+
return f"🚨 {base_rec} Analyse BiomedBERT indique une attention médicale prioritaire."
|
594 |
+
elif level == "modéré":
|
595 |
+
return f"⚠️ {base_rec} Surveillance médicale recommandée."
|
596 |
+
else:
|
597 |
+
return base_rec
|
598 |
+
|
599 |
+
# Dictionnaire des noms complets (à ajouter si pas déjà présent)
|
600 |
+
CLASS_NAMES_FULL = {
|
601 |
+
"mel": "Melanoma",
|
602 |
+
"bcc": "Basal Cell Carcinoma",
|
603 |
+
"akiec": "Actinic Keratosis",
|
604 |
+
"bkl": "Benign Keratosis",
|
605 |
+
"df": "Dermatofibroma",
|
606 |
+
"nv": "Melanocytic Nevus",
|
607 |
+
"vasc": "Vascular Lesion"
|
608 |
+
}
|
609 |
+
|
610 |
+
# --- Fin Bert Doctor
|
611 |
+
|
612 |
+
|
613 |
+
|
614 |
# ---- GESTION ASYNCHRONE / ÉTAT ----
|
615 |
current_image = None
|
616 |
current_predictions = None
|
|
|
637 |
"", # output_text vide
|
638 |
gr.update(value="", visible=False), # output_warning masqué
|
639 |
empty_fig, # Figure vide au lieu de None
|
640 |
+
"❌ Erreur: Aucune image fournie.",
|
641 |
+
"" # Nouveau output pour BiomedBERT
|
642 |
)
|
643 |
|
644 |
try:
|
|
|
653 |
# Probabilité de mélanome
|
654 |
mel_idx = CLASS_NAMES.index("mel")
|
655 |
mel_prob = ensemble_probs[mel_idx] * 100
|
656 |
+
confidence = ensemble_probs[top_class_idx] * 100
|
657 |
+
|
658 |
+
# NOUVELLE: Analyse médicale avec BiomedBERT
|
659 |
+
medical_analysis = get_medical_analysis(top_class_name, confidence, mel_prob)
|
660 |
|
661 |
# Description
|
662 |
desc_top = description.get(top_class_name, "")
|
|
|
703 |
'''
|
704 |
warning_visible = True
|
705 |
|
706 |
+
# NOUVEAU: HTML pour l'analyse médicale BiomedBERT
|
707 |
+
biomed_html = f'''
|
708 |
+
<div class="medical-analysis" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 10px; margin-top: 10px;">
|
709 |
+
<h3 style="margin: 0 0 10px 0; display: flex; align-items: center;">
|
710 |
+
🧬 Analyse Médicale BiomedBERT
|
711 |
+
</h3>
|
712 |
+
<div style="background: rgba(255,255,255,0.1); padding: 10px; border-radius: 5px;">
|
713 |
+
<p><strong>Statut:</strong> {medical_analysis['status']}</p>
|
714 |
+
<p><strong>Analyse:</strong> {medical_analysis['analysis']}</p>
|
715 |
+
<p><strong>Recommandation:</strong> {medical_analysis['recommendation']}</p>
|
716 |
+
</div>
|
717 |
+
</div>
|
718 |
+
'''
|
719 |
+
|
720 |
# Création du graphique Plotly
|
721 |
probabilities = [round(ensemble_probs[i] * 100, 2) for i in range(len(CLASS_NAMES))]
|
722 |
|
|
|
727 |
go.Bar(
|
728 |
x=CLASS_NAMES,
|
729 |
y=probabilities,
|
730 |
+
text=[f'{p:.2f}%' for p in probabilities],
|
731 |
+
textposition='outside',
|
732 |
marker_color=colors,
|
733 |
hovertemplate='<b>%{x}</b><br>Probabilité: %{y:.2f}%<extra></extra>'
|
734 |
)
|
735 |
])
|
736 |
|
737 |
fig.update_layout(
|
|
|
738 |
xaxis_title="Classes",
|
739 |
yaxis_title="Probabilité (%)",
|
740 |
+
yaxis=dict(range=[0, max(probabilities) * 1.15]),
|
741 |
height=450,
|
742 |
template="plotly_white",
|
743 |
showlegend=False,
|
744 |
font=dict(size=12),
|
745 |
+
margin=dict(l=50, r=50, t=70, b=100)
|
746 |
)
|
747 |
|
|
|
748 |
fig.update_xaxes(tickangle=45)
|
749 |
|
750 |
return (
|
751 |
global_diag_html,
|
752 |
output_text_html,
|
753 |
gr.update(value=warning_html, visible=warning_visible),
|
754 |
+
fig,
|
755 |
+
"✅ Analyse terminée.",
|
756 |
+
biomed_html # NOUVEAU: Retour de l'analyse BiomedBERT
|
757 |
)
|
758 |
|
759 |
except Exception as e:
|
|
|
766 |
showlegend=False
|
767 |
)
|
768 |
|
769 |
+
error_biomed_html = f'''
|
770 |
+
<div class="medical-analysis" style="background: #ffebee; color: #d32f2f; padding: 15px; border-radius: 10px; border: 1px solid #ef9a9a;">
|
771 |
+
<h3>🧬 Analyse Médicale BiomedBERT</h3>
|
772 |
+
<p>❌ Erreur lors de l'analyse médicale: {str(e)}</p>
|
773 |
+
</div>
|
774 |
+
'''
|
775 |
+
|
776 |
return (
|
777 |
f'<div class="diagnostic-global"><h2>Erreur: {str(e)}</h2></div>',
|
778 |
"",
|
|
|
781 |
❌ Une erreur est survenue : {str(e)}
|
782 |
</div>
|
783 |
''', visible=True),
|
784 |
+
error_fig,
|
785 |
+
f"❌ Erreur: {str(e)}",
|
786 |
+
error_biomed_html # NOUVEAU: Erreur BiomedBERT
|
787 |
)
|
788 |
+
|
789 |
def generate_gradcam_ui(progress=gr.Progress()):
|
790 |
global current_image, current_predictions
|
791 |
if current_image is None or current_predictions is None:
|
|
|
888 |
|
889 |
# Configuration correcte du BarPlot
|
890 |
output_plot = gr.Plot(label="Probabilités par classe")
|
891 |
+
# NOUVEAU: Output pour l'analyse BiomedBERT
|
892 |
+
output_medical = gr.HTML(label="🧬 Analyse Médicale Avancée")
|
893 |
|
894 |
gr.Markdown(f"Ensemble de modèles utilisés : {', '.join(models_status) if models_status else 'AUCUN'}")
|
895 |
gr.HTML(value="""
|
|
|
905 |
quick_btn.click(
|
906 |
fn=quick_predict_ui,
|
907 |
inputs=input_image,
|
908 |
+
outputs=[output_label, output_text, output_warning, output_plot, output_status, output_medical]
|
909 |
)
|
910 |
|
911 |
gradcam_btn.click(
|