File size: 11,747 Bytes
a826b39
 
 
 
 
 
 
 
 
 
11e7296
a826b39
 
 
 
11e7296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
11e7296
 
a826b39
 
11e7296
a826b39
11e7296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
 
11e7296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
 
 
 
11e7296
 
a826b39
11e7296
a826b39
 
 
 
 
 
 
 
 
 
 
 
 
 
11e7296
a826b39
 
 
11e7296
 
a826b39
 
 
11e7296
a826b39
 
11e7296
a826b39
11e7296
 
 
 
 
 
a826b39
11e7296
 
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
 
 
11e7296
 
 
 
 
 
 
 
 
a826b39
 
 
 
11e7296
6486045
11e7296
 
 
 
 
a826b39
11e7296
6486045
 
a826b39
11e7296
a826b39
 
 
11e7296
a826b39
 
 
11e7296
 
a826b39
 
11e7296
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
 
11e7296
a826b39
11e7296
a826b39
11e7296
a826b39
 
 
56fc38d
 
 
 
 
 
 
 
 
 
 
 
 
a826b39
c9c1406
a826b39
11e7296
 
 
 
 
 
a826b39
11e7296
a826b39
11e7296
 
 
 
 
 
a826b39
 
11e7296
a826b39
 
 
11e7296
a826b39
 
11e7296
 
 
 
 
 
 
 
 
a826b39
 
 
11e7296
a826b39
 
11e7296
a826b39
 
 
11e7296
a826b39
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import gradio as gr
import tensorflow as tf
import numpy as np
from PIL import Image
import json
from huggingface_hub import hf_hub_download

# ============================================
# Configurações do modelo
# ============================================
REPO_ID = "raysarocha/plant-resnet50-38classes"  # Seu modelo recém-deployado!

# ============================================
# Carregamento do modelo
# ============================================
def load_model():
    """Carrega o modelo uma única vez e mantém em cache"""
    print("🔄 Baixando e carregando modelo...")
    
    # Baixa os arquivos
    cfg_path = hf_hub_download(REPO_ID, "config.json")
    model_path = hf_hub_download(REPO_ID, "model.keras")
    
    # Carrega configuração
    with open(cfg_path, "r") as f:
        cfg = json.load(f)
    
    # Carrega modelo
    model = tf.keras.models.load_model(model_path)
    print("✅ Modelo carregado com sucesso!")
    
    return model, cfg

# Carrega o modelo
model, cfg = load_model()

# ============================================
# Dicionário de nomes amigáveis e recomendações
# ============================================
PLANT_INFO = {
    "Apple___Apple_scab": {
        "name": "🍎 Maçã - Sarna",
        "healthy": False,
        "description": "Doença fúngica que causa manchas escuras nas folhas e frutos",
        "treatment": "• Remova folhas infectadas\n• Aplique fungicida à base de cobre\n• Melhore a circulação de ar"
    },
    "Apple___Black_rot": {
        "name": "🍎 Maçã - Podridão Negra",
        "healthy": False,
        "description": "Infecção fúngica que causa podridão em frutos e folhas",
        "treatment": "• Pode galhos infectados\n• Remova frutos mumificados\n• Use fungicida preventivo"
    },
    "Apple___Cedar_apple_rust": {
        "name": "🍎 Maçã - Ferrugem do Cedro",
        "healthy": False,
        "description": "Doença que causa manchas alaranjadas nas folhas",
        "treatment": "• Remova cedros próximos se possível\n• Aplique fungicida na primavera\n• Escolha variedades resistentes"
    },
    "Apple___healthy": {
        "name": "🍎 Maçã - Saudável",
        "healthy": True,
        "description": "Planta em bom estado de saúde",
        "treatment": "• Continue com os cuidados regulares\n• Mantenha boa irrigação\n• Faça podas preventivas"
    },
    "Tomato___Bacterial_spot": {
        "name": "🍅 Tomate - Mancha Bacteriana",
        "healthy": False,
        "description": "Infecção bacteriana que causa manchas nas folhas",
        "treatment": "• Evite molhar as folhas\n• Use sementes certificadas\n• Aplique cobre preventivamente"
    },
    "Tomato___Early_blight": {
        "name": "🍅 Tomate - Requeima Precoce",
        "healthy": False,
        "description": "Doença fúngica com manchas em anéis concêntricos",
        "treatment": "• Remova folhas afetadas\n• Aplique fungicida\n• Faça rotação de culturas"
    },
    "Tomato___healthy": {
        "name": "🍅 Tomate - Saudável",
        "healthy": True,
        "description": "Planta em bom estado de saúde",
        "treatment": "• Mantenha irrigação regular\n• Adube adequadamente\n• Monitore pragas"
    },
    "Potato___Early_blight": {
        "name": "🥔 Batata - Requeima Precoce",
        "healthy": False,
        "description": "Manchas escuras com anéis concêntricos nas folhas",
        "treatment": "• Use fungicida preventivo\n• Evite irrigação excessiva\n• Destrua restos culturais"
    },
    "Potato___Late_blight": {
        "name": "🥔 Batata - Requeima Tardia",
        "healthy": False,
        "description": "Doença devastadora que causa manchas aquosas",
        "treatment": "• Aplique fungicida imediatamente\n• Remova plantas infectadas\n• Melhore drenagem do solo"
    },
    "Potato___healthy": {
        "name": "🥔 Batata - Saudável",
        "healthy": True,
        "description": "Planta em bom estado de saúde",
        "treatment": "• Continue monitorando\n• Faça amontoa regular\n• Controle irrigação"
    }
}

# Preenche informações padrão para classes não detalhadas
for class_key in cfg["label2id"].keys():
    if class_key not in PLANT_INFO:
        if "healthy" in class_key.lower():
            PLANT_INFO[class_key] = {
                "name": class_key.replace("___", " - ").replace("_", " "),
                "healthy": True,
                "description": "Planta aparentemente saudável",
                "treatment": "• Mantenha os cuidados regulares\n• Continue monitorando"
            }
        else:
            PLANT_INFO[class_key] = {
                "name": class_key.replace("___", " - ").replace("_", " "),
                "healthy": False,
                "description": "Possível problema detectado na planta",
                "treatment": "• Consulte um agrônomo\n• Isole a planta se possível\n• Evite excesso de umidade"
            }

# ============================================
# Função de classificação
# ============================================
def classify_plant(image):
    """Classifica a imagem e retorna diagnóstico detalhado"""
    
    if image is None:
        return None, "", ""
    
    # Preprocessamento
    img = Image.fromarray(image).convert("RGB")
    img = img.resize((cfg["image_size"], cfg["image_size"]))
    arr = np.array(img).astype("float32") * cfg["rescale"]
    arr = np.expand_dims(arr, axis=0)
    
    # Predição
    predictions = model(arr)
    probs = tf.nn.softmax(predictions[0]).numpy()
    
    # Top 5 resultados
    top_5_idx = np.argsort(probs)[-5:][::-1]
    
    # Formata resultados
    results = {}
    for idx in top_5_idx:
        class_name = cfg["id2label"][str(idx)]
        info = PLANT_INFO.get(class_name, {})
        friendly_name = info.get("name", class_name)
        confidence = float(probs[idx])
        results[friendly_name] = confidence
    
    # Pega informação da classe mais provável
    top_class = cfg["id2label"][str(top_5_idx[0])]
    top_confidence = float(probs[top_5_idx[0]])
    top_info = PLANT_INFO.get(top_class, {})
    
    # Cria card de diagnóstico
    if top_info.get("healthy", False):
        status_icon = "✅"
        status_text = "Planta Saudável"
        card_color = "#10b981"  # Verde
        bg_color = "#f0fdf4"
    else:
        status_icon = "⚠️"
        status_text = "Atenção Necessária"
        card_color = "#f59e0b"  # Laranja
        bg_color = "#fef3c7"
    
    diagnosis_html = f"""
    <div style='padding: 20px; border-radius: 12px; background: {bg_color}; border: 2px solid {card_color}; margin-bottom: 20px;'>
        <h2 style='color: {card_color}; margin: 0 0 10px 0; font-size: 24px;'>
            {status_icon} {status_text}
        </h2>
        <h3 style='color: #374151; margin: 10px 0;'>{top_info.get('name', top_class)}</h3>
        <p style='color: #6b7280; margin: 10px 0;'>Confiança: {top_confidence:.1%}</p>
        <hr style='border: 1px solid {card_color}; opacity: 0.3; margin: 15px 0;'>
        <p style='color: #4b5563; margin: 10px 0;'><strong>Descrição:</strong><br>{top_info.get('description', 'Informação não disponível')}</p>
    </div>
    """
    
    # Recomendações
    treatment_html = f"""
    <div style='padding: 15px; border-radius: 8px; background: #f9fafb; border: 1px solid #e5e7eb;'>
        <h3 style='color: #1f2937; margin: 0 0 10px 0;'>📋 Recomendações:</h3>
        <pre style='color: #4b5563; margin: 0; white-space: pre-wrap; font-family: sans-serif; line-height: 1.5;'>{top_info.get('treatment', '• Consulte um especialista para orientações específicas')}</pre>
    </div>
    """
    
    return results, diagnosis_html, treatment_html

# ============================================
# Interface Gradio
# ============================================
with gr.Blocks(
    title="Plant Identifier & Health Checker 🌿",
    theme=gr.themes.Soft(
        primary_hue="green",
        secondary_hue="emerald",
    )
) as demo:
    
    gr.Markdown("""
    # 🌿 Plant Identifier & Health Checker
    ### Identificação e Análise de Saúde de Plantas
    
    Upload uma foto da sua planta para receber um diagnóstico instantâneo e recomendações de tratamento.
    """)
    
    with gr.Row():
        with gr.Column(scale=1):
            input_image = gr.Image(
                label="📷 Upload da Imagem",
                type="numpy",
                height=400,
                sources=["upload", "webcam", "clipboard"]
            )
            
            with gr.Row():
                clear_btn = gr.Button("🗑️ Limpar", variant="secondary")
                submit_btn = gr.Button("🔍 Analisar", variant="primary", scale=2)
            
            gr.Markdown("""
            **💡 Dicas para melhores resultados:**
            - Use boa iluminação natural
            - Foque nas folhas afetadas
            - Evite sombras fortes
            - Aproxime-se da área problemática
            """)
            
        with gr.Column(scale=1):
            diagnosis_output = gr.HTML(
                label="Diagnóstico",
                value="<div style='padding: 40px; text-align: center; color: #9ca3af;'><h3>🔍 Aguardando imagem...</h3><p>Faça upload de uma foto para começar</p></div>"
            )
            treatment_output = gr.HTML(label="Tratamento Recomendado")
            confidence_output = gr.Label(
                label="📊 Análise de Probabilidade",
                num_top_classes=5
            )
    
    # # Exemplos
    # gr.Markdown("### 🖼️ Exemplos")
    # gr.Examples(
    #     examples=[
    #         ["https://www.gardeningknowhow.com/wp-content/uploads/2017/06/apple-scab-lesions.jpg"],
    #         ["https://www.gardeningknowhow.com/wp-content/uploads/2020/11/tomato-early-blight.jpg"],
    #         ["https://www.gardeningknowhow.com/wp-content/uploads/2019/08/potato-blight-400x300.jpg"],
    #     ],
    #     inputs=input_image,
    #     outputs=[confidence_output, diagnosis_output, treatment_output],
    #     fn=classify_plant,
    #     cache_examples=True
    # )
    
    gr.Markdown("""
    ---
    ### ℹ️ Sobre o Modelo
    
    - **Arquitetura:** ResNet50
    - **Classes:** 38 tipos de plantas e doenças
    - **Plantas incluídas:** Maçã, Tomate, Batata, Uva, Milho, Pêssego, Pimentão, Morango e mais
    - **Precisão:** ~98% no conjunto de validação
    
    ### 🔗 Links Úteis
    - [Modelo no HuggingFace](https://huggingface.co/raysarocha/plant-resnet50-38classes)
    - [Relatório Técnico](#)
    - [Dataset Original](https://www.kaggle.com/datasets/vipoooool/new-plant-diseases-dataset)
    ---
    <p style='text-align: center; color: #9ca3af;'>
        Desenvolvido com ❤️ por Raysa Rocha | 2024
    </p>
    """)
    
    # Eventos
    submit_btn.click(
        fn=classify_plant,
        inputs=input_image,
        outputs=[confidence_output, diagnosis_output, treatment_output]
    )
    
    clear_btn.click(
        fn=lambda: (None, 
                   "<div style='padding: 40px; text-align: center; color: #9ca3af;'><h3>🔍 Aguardando imagem...</h3></div>",
                   "", 
                   None),
        outputs=[input_image, diagnosis_output, treatment_output, confidence_output]
    )
    
    # Análise automática ao fazer upload
    input_image.change(
        fn=classify_plant,
        inputs=input_image,
        outputs=[confidence_output, diagnosis_output, treatment_output]
    )

# Inicia a aplicação
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        share=False
    )