File size: 5,181 Bytes
fd204ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444d7a7
 
 
fd204ac
 
 
 
444d7a7
 
 
 
 
 
fd204ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444d7a7
fd204ac
 
 
 
 
 
 
444d7a7
fd204ac
 
 
 
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
# ================================
# 0. PATCH pour huggingface_hub (contourne l'absence de HfFolder)
# ================================
import huggingface_hub
if not hasattr(huggingface_hub, 'HfFolder'):
    class HfFolder:
        _token = None
        @staticmethod
        def get_token():
            return HfFolder._token
        @staticmethod
        def save_token(token):
            HfFolder._token = token
    huggingface_hub.HfFolder = HfFolder

# ================================
# 1. PATCH pour contourner le bug de Gradio 4.44.0
#    (TypeError: argument of type 'bool' is not iterable)
# ================================
import gradio_client.utils

original_get_type = gradio_client.utils.get_type

def patched_get_type(schema):
    if isinstance(schema, bool):
        return "boolean"
    return original_get_type(schema)

gradio_client.utils.get_type = patched_get_type

# ================================
# 2. IMPORTS STANDARDS
# ================================
import gradio as gr
import tensorflow as tf
import numpy as np
from PIL import Image

# Forcer la précision float32 (évite les warnings de mixed precision sur CPU)
tf.keras.mixed_precision.set_global_policy('float32')

# ================================
# 3. CHARGEMENT DU MODÈLE (72 classes)
# ================================
MODEL_PATH = "final_model.keras"
# Charger le modèle sans compiler pour éviter l'avertissement sur l'optimiseur
model = tf.keras.models.load_model(MODEL_PATH, compile=False)

# Recompiler avec une configuration simple (nécessaire pour faire des prédictions)
# On utilise une perte factice car on ne fera pas d'entraînement
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# ================================
# 4. NOMS DES CLASSES (issus de l'entraînement)
# ================================
class_names = [
    "Apple___alternaria_leaf_spot",
    "Apple___black_rot",
    "Apple___brown_spot",
    "Apple___gray_spot",
    "Apple___healthy",
    "Apple___rust",
    "Apple___scab",
    "Bell_pepper___bacterial_spot",
    "Bell_pepper___healthy",
    "Blueberry___healthy",
    "Cassava___bacterial_blight",
    "Cassava___brown_streak_disease",
    "Cassava___green_mottle",
    "Cassava___healthy",
    "Cassava___mosaic_disease",
    "Cherry___healthy",
    "Cherry___powdery_mildew",
    "Coffee___healthy",
    "Coffee___red_spider_mite",
    "Coffee___rust",
    "Corn___common_rust",
    "Corn___gray_leaf_spot",
    "Corn___healthy",
    "Corn___northern_leaf_blight",
    "Grape___Leaf_blight",
    "Grape___black_measles",
    "Grape___black_rot",
    "Grape___healthy",
    "Orange___citrus_greening",
    "Peach___bacterial_spot",
    "Peach___healthy",
    "Potato___bacterial_wilt",
    "Potato___early_blight",
    "Potato___healthy",
    "Potato___late_blight",
    "Potato___leafroll_virus",
    "Potato___mosaic_virus",
    "Potato___nematode",
    "Potato___pests",
    "Potato___phytophthora",
    "Raspberry___healthy",
    "Rice___bacterial_blight",
    "Rice___blast",
    "Rice___brown_spot",
    "Rice___tungro",
    "Rose___healthy",
    "Rose___rust",
    "Rose___slug_sawfly",
    "Soybean___healthy",
    "Squash___powdery_mildew",
    "Strawberry___healthy",
    "Strawberry___leaf_scorch",
    "Sugercane___healthy",
    "Sugercane___mosaic",
    "Sugercane___red_rot",
    "Sugercane___rust",
    "Sugercane___yellow_leaf",
    "Tomato___bacterial_spot",
    "Tomato___early_blight",
    "Tomato___healthy",
    "Tomato___late_blight",
    "Tomato___leaf_curl",
    "Tomato___leaf_mold",
    "Tomato___mosaic_virus",
    "Tomato___septoria_leaf_spot",
    "Tomato___spider_mites",
    "Tomato___target_spot",
    "Watermelon___anthracnose",
    "Watermelon___downy_mildew",
    "Watermelon___healthy",
    "Watermelon___mosa"
]

# ================================
# 5. FONCTION DE PRÉDICTION
# ================================
def preprocess_image(img):
    """Redimensionne et normalise l'image pour le modèle EfficientNet."""
    img = img.resize((224, 224))
    img_array = np.array(img)
    img_array = tf.keras.applications.efficientnet.preprocess_input(img_array)
    img_array = np.expand_dims(img_array, axis=0)
    return img_array

def predict(img):
    """
    img : image PIL fournie par gr.Image(type="pil")
    Retourne un dictionnaire {classe: probabilité} pour le composant gr.Label
    """
    processed = preprocess_image(img)
    preds = model.predict(processed, verbose=0)[0]
    results = {class_names[i]: float(preds[i]) for i in range(len(class_names))}
    return results

# ================================
# 6. INTERFACE GRADIO (sans allow_flagging)
# ================================
iface = gr.Interface(
    fn=predict,
    inputs=gr.Image(type="pil", label="Chargez une image de feuille"),
    outputs=gr.Label(num_top_classes=3, label="Maladie prédite (top 3)"),
    title="Classification des maladies des plantes (72 classes)",
    description="Chargez une photo de feuille et le modèle prédira la maladie parmi 72 classes. Modèle basé sur EfficientNetB0 avec fine-tuning.",
    examples=None
)

if __name__ == "__main__":
    iface.launch(share=True)