File size: 6,772 Bytes
06eef07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import torch
from transformers import ViTFeatureExtractor, ViTForImageClassification
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import gradio as gr
import io
import base64

MODEL_NAME = "ahishamm/vit-base-HAM-10000-sharpened-patch-32"
feature_extractor = ViTFeatureExtractor.from_pretrained(MODEL_NAME)
model = ViTForImageClassification.from_pretrained(MODEL_NAME)
model.eval()

CLASSES = [
    "Queratosis actínica / Bowen",      # 0
    "Carcinoma células basales",        # 1
    "Lesión queratósica benigna",       # 2
    "Dermatofibroma",                   # 3
    "Melanoma maligno",                 # 4
    "Nevus melanocítico",               # 5
    "Lesión vascular"                   # 6
]
RISK_LEVELS = {
    0: {'level': 'Moderado', 'color': '#ffaa00', 'weight': 0.6},
    1: {'level': 'Alto', 'color': '#ff4444', 'weight': 0.8},
    2: {'level': 'Bajo', 'color': '#44ff44', 'weight': 0.1},
    3: {'level': 'Bajo', 'color': '#44ff44', 'weight': 0.1},
    4: {'level': 'Crítico', 'color': '#cc0000', 'weight': 1.0},
    5: {'level': 'Bajo', 'color': '#44ff44', 'weight': 0.1},
    6: {'level': 'Bajo', 'color': '#44ff44', 'weight': 0.1}
}

def analizar_lesion_vit_web(img):
    inputs = feature_extractor(img, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs)
        probs = outputs.logits.softmax(dim=-1).cpu().numpy()[0]
    pred_idx = int(np.argmax(probs))
    pred_clase = CLASSES[pred_idx]
    confianza = probs[pred_idx]
    cancer_risk_score = sum(probs[i] * RISK_LEVELS[i]['weight'] for i in range(7))
    melanoma_risk = probs[4]
    bcc_risk = probs[1]
    precancer_risk = probs[0]
    benign_total = sum(probs[i] for i in [2,3,5,6])

    colors_bars = [RISK_LEVELS[i]['color'] for i in range(7)]
    fig, ax = plt.subplots(figsize=(8,3))
    ax.bar(CLASSES, probs*100, color=colors_bars)
    ax.set_title("Probabilidad por tipo de lesión")
    ax.set_ylabel("Probabilidad (%)")
    ax.set_xticklabels(CLASSES, rotation=45, ha='right')
    ax.grid(axis='y', alpha=0.2)
    plt.tight_layout()
    buf = io.BytesIO()
    plt.savefig(buf, format="png")
    plt.close(fig)
    buf.seek(0)
    img_bytes = buf.getvalue()
    img_b64 = base64.b64encode(img_bytes).decode("utf-8")
    html_chart = f'<img src="data:image/png;base64,{img_b64}" style="max-width:100%"/>'

    urgency = ""
    recommendation = ""
    timeframe = ""
    if cancer_risk_score > 0.6:
        urgency = "🚨 <b>CRÍTICO</b>"
        recommendation = "Derivación INMEDIATA a oncología dermatológica"
        timeframe = "En 24-48 horas máximo"
    elif cancer_risk_score > 0.4:
        urgency = "⚠️ <b>ALTO RIESGO</b>"
        recommendation = "Consulta urgente con dermatólogo especialista"
        timeframe = "En 1 semana máximo"
    elif cancer_risk_score > 0.2:
        urgency = "📋 <b>RIESGO MODERADO</b>"
        recommendation = "Evaluación dermatológica programada"
        timeframe = "En 2-4 semanas"
    else:
        urgency = "✅ <b>BAJO RIESGO</b>"
        recommendation = "Seguimiento de rutina"
        timeframe = "En 3-6 meses"

    informe = f"""

    <div style="font-family:sans-serif; max-width:700px; margin:auto">

    <h2>🏥 INFORME DE ANÁLISIS DERMATOLÓGICO CON IA</h2>

    <b>📊 Diagnóstico principal:</b> {pred_clase}<br>

    <b>🎯 Confianza del modelo:</b> {confianza:.1%}<br>

    <b>📈 Score de riesgo oncológico:</b> {cancer_risk_score:.1%}<br>

    <br>

    <b>⚠️ Análisis de riesgo detallado:</b><br>

    &emsp;🔴 Melanoma maligno: {melanoma_risk:.1%}<br>

    &emsp;🟠 Carcinoma células basales: {bcc_risk:.1%}<br>

    &emsp;🟡 Lesión pre-cancerosa: {precancer_risk:.1%}<br>

    &emsp;🟢 Lesiones benignas: {benign_total:.1%}<br>

    <br>

    <b>🩺 Evaluación clínica:</b><br>

    &emsp;{urgency}<br>

    &emsp;💡 Recomendación: {recommendation}<br>

    &emsp;⏰ Plazo: {timeframe}<br>

    <br>

    <b>🔍 Características analizadas:</b><br>

    """
    if melanoma_risk > 0.3:
        informe += "• ⚠️  Posibles irregularidades sugestivas de melanoma<br>• 🔍 Asimetría o variación de color detectada<br>"
    if bcc_risk > 0.25:
        informe += "• 🔍 Características compatibles con carcinoma basocelular<br>"
    if precancer_risk > 0.25:
        informe += "• 🔍 Posible queratosis actínica (lesión pre-maligna)<br>"
    if benign_total > 0.6:
        informe += "• ✅ Características predominantemente benignas<br>"

    informe += "<br><b>📊 Diagnósticos diferenciales (ordenados por probabilidad):</b><ul>"
    sorted_indices = np.argsort(probs)[::-1]
    for i, idx in enumerate(sorted_indices):
        marker = "🎯" if i==0 else f"{i+1}."
        prob_bars = int(probs[idx] * 30)
        bar_visual = "█" * prob_bars + "░" * (30 - prob_bars)
        risk_indicator = ("🔴" if idx in [1,4] else "🟡" if idx==0 else "🟢")
        informe += f"<li>{marker} {risk_indicator} {CLASSES[idx]}{probs[idx]:.1%} <code>{bar_visual}</code></li>"
    informe += "</ul>"

    informe += """

    <br>

    <b>📋 Información técnica:</b><br>

    • Modelo: ViT-Base (HAM10000, sharpened)<br>

    • Precisión validada: 83.7%<br>

    • Preprocesamiento: Optimizado para dermatoscopia<br>

    • Clases detectadas: 7 tipos de lesiones cutáneas<br>

    <br>

    <b>📝 Notas clínicas:</b><br>

    """
    if confianza < 0.7:
        informe += "• ⚠️  Confianza moderada - considerar segunda opinión<br>"
    if cancer_risk_score > 0.3:
        informe += "• 🩺 Documentar evolución con fotografías seriadas<br>"
    informe += "• 📏 Regla ABCDE: Evaluar Asimetría, Bordes, Color, Diámetro, Evolución<br>"

    informe += """

    <br><hr>

    <b>⚕️ ADVERTENCIA MÉDICA</b><br>

    • Este análisis es una HERRAMIENTA DE APOYO diagnóstico.<br>

    • NO sustituye la evaluación clínica de un dermatólogo.<br>

    • Ante cualquier duda, consulte con un profesional médico.<br>

    • La decisión terapéutica final corresponde al médico tratante.<br>

    </div>

    """
    return informe, html_chart

demo = gr.Interface(
    fn=analizar_lesion_vit_web,
    inputs=gr.Image(type="pil", label="Sube una imagen de la lesión"),
    outputs=[gr.HTML(label="Informe detallado"), gr.HTML(label="Gráfico de barras")],
    title="Detector de Cáncer de Piel IA (HAM10000, ViT)",
    description="Sube una imagen dermatológica y obtén un informe detallado generado por IA (ViT-HAM10000, accuracy ~83.7%)",
    flagging_mode="never"
)

if __name__ == "__main__":
    demo.launch()