JAMC980-UNAH commited on
Commit
253c53a
·
1 Parent(s): 195dbed

Reapply local changes after pull

Browse files
Files changed (6) hide show
  1. app.py +268 -0
  2. clases_orden_oxford.json +104 -0
  3. flores_modelo (2).h5 +3 -0
  4. img2.png +0 -0
  5. img3.png +3 -0
  6. package-lock.json +6 -0
app.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import tensorflow as tf
3
+ import numpy as np
4
+ from PIL import Image
5
+ import json
6
+ import requests
7
+ import io
8
+ import base64
9
+ import os
10
+
11
+ # ===== CONFIGURACIÓN =====
12
+ PLANTNET_CONFIG = {
13
+ "base_url": "https://my-api.plantnet.org/v2/identify/all",
14
+ "api_key": "2b10GtUDt6p1whX94wlEiR3CG",
15
+ "timeout": 10,
16
+ "lang": "es" # Español
17
+ }
18
+
19
+ # ===== VARIABLES GLOBALES =====
20
+ MODEL_LOADED = False
21
+ model = None
22
+ labels = []
23
+
24
+ # ===== FUNCIONES DE UTILIDAD =====
25
+ def load_model():
26
+ global model, labels, MODEL_LOADED
27
+ try:
28
+ model = tf.keras.models.load_model("flores_modelo (2).h5")
29
+ with open("clases_orden_oxford.json", "r") as f:
30
+ class_indices = json.load(f)
31
+ labels = [None] * len(class_indices)
32
+ for class_name, idx in class_indices.items():
33
+ labels[idx] = class_name.replace("_", " ").title()
34
+ MODEL_LOADED = True
35
+ except Exception as e:
36
+ print(f"Error al cargar el modelo: {e}")
37
+ MODEL_LOADED = False
38
+
39
+ def image_to_base64(image_path):
40
+ try:
41
+ with open(image_path, "rb") as img_file:
42
+ return base64.b64encode(img_file.read()).decode('utf-8')
43
+ except:
44
+ return None
45
+
46
+ def preprocess_image(image):
47
+ image = image.resize((224, 224))
48
+ img_array = np.array(image) / 255.0
49
+ if img_array.shape[-1] == 4:
50
+ img_array = img_array[..., :3]
51
+ return np.expand_dims(img_array, axis=0)
52
+
53
+ # =====സ
54
+
55
+ # ===== INTEGRACIÓN CON PLANTNET =====
56
+ def get_flower_info_from_plantnet(flower_name, image_array):
57
+ try:
58
+ image_pil = Image.fromarray((image_array[0] * 255).astype(np.uint8))
59
+ img_byte_arr = io.BytesIO()
60
+ image_pil.save(img_byte_arr, format='JPEG')
61
+ img_byte_arr.seek(0)
62
+
63
+ url = f"{PLANTNET_CONFIG['base_url']}?api-key={PLANTNET_CONFIG['api_key']}&lang={PLANTNET_CONFIG['lang']}"
64
+ files = {'images': ('image.jpg', img_byte_arr, 'image/jpeg')}
65
+ data = {'organs': 'flower'}
66
+
67
+ response = requests.post(url, files=files, data=data, timeout=PLANTNET_CONFIG['timeout'])
68
+ if response.status_code == 200:
69
+ return parse_plantnet_response(response.json(), flower_name)
70
+ else:
71
+ print(f"Error en PlantNet: {response.status_code}")
72
+ return get_fallback_info(flower_name)
73
+ except requests.exceptions.Timeout:
74
+ print("Tiempo de espera agotado en PlantNet")
75
+ return get_fallback_info(flower_name)
76
+ except Exception as e:
77
+ print(f"PlantNet error: {e}")
78
+ return get_fallback_info(flower_name)
79
+
80
+ def parse_plantnet_response(data, flower_name):
81
+ if 'results' in data and len(data['results']) > 0:
82
+ results = data['results'][:3]
83
+ info = f"""
84
+ <div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]">
85
+ <div class="flex items-center justify-center">
86
+ <h2 class="text-yellow-400 font-bold text-2xl">🌸 {flower_name}</h2>
87
+ </div>
88
+ <div>
89
+ <h3 class="text-yellow-400 font-bold text-xl mt-4">📊 Identificación Científica</h3>
90
+ """
91
+ for i, result in enumerate(results, 1):
92
+ species = result.get('species', {})
93
+ scientific_name = species.get('scientificNameWithoutAuthor', 'N/A')
94
+ authorship = species.get('scientificNameAuthorship', '')
95
+ common_names = species.get('commonNames', [])
96
+ family = species.get('family', {}).get('scientificNameWithoutAuthor', 'N/A')
97
+ genus = species.get('genus', {}).get('scientificNameWithoutAuthor', 'N/A')
98
+ score = result.get('score', 0)
99
+ common_names_str = ', '.join(common_names[:3]) if common_names else 'No disponible'
100
+
101
+ info += f"""
102
+ <div class="flex items-start mt-4">
103
+ <div class="text-white mr-4">#{i}</div>
104
+ <div>
105
+ <h4 class="text-white font-semibold">{scientific_name} {authorship}</h4>
106
+ <div class="relative h-2 bg-gray-200 rounded mt-2">
107
+ <div class="absolute h-full bg-yellow-400 rounded" style="width: {score*100}%"></div>
108
+ <span class="text-white text-sm mt-2 block">{score:.1%} confianza</span>
109
+ </div>
110
+ <div class="grid grid-cols-1 gap-2 mt-2">
111
+ <div class="text-white"><strong>Nombres comunes:</strong> {common_names_str}</div>
112
+ <div class="text-white"><strong>Familia:</strong> {family}</div>
113
+ <div class="text-white"><strong>Género:</strong> {genus}</div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ """
118
+ info += """
119
+ </div>
120
+ <div class="mt-6">
121
+ <h3 class="text-yellow-400 font-bold text-xl">🌿 Cuidados Generales</h3>
122
+ <div class="grid grid-cols-2 gap-4 mt-2">
123
+ <div class="flex items-start"><div class="text-2xl mr-2">☀️</div><div class="text-white"><strong>Luz:</strong> Luz solar directa o indirecta</div></div>
124
+ <div class="flex items-start"><div class="text-2xl mr-2">💧</div><div class="text-white"><strong>Riego:</strong> Mantener húmedo, evitar exceso</div></div>
125
+ <div class="flex items-start"><div class="text-2xl mr-2">🌡️</div><div class="text-white"><strong>Temperatura:</strong> Evitar cambios bruscos</div></div>
126
+ <div class="flex items-start"><div class="text-2xl mr-2">🌱</div><div class="text-white"><strong>Suelo:</strong> Bien drenado y rico en nutrientes</div></div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ """
131
+ return info
132
+ return get_fallback_info(flower_name)
133
+
134
+ def get_fallback_info(flower_name):
135
+ return f"""
136
+ <div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]">
137
+ <div class="flex items-center justify-between">
138
+ <h2 class="text-yellow-400 font-bold text-2xl">🌸 {flower_name}</h2>
139
+ <div class="bg-red-600 text-white px-2 py-1 rounded">PlantNet no disponible</div>
140
+ </div>
141
+ <div class="mt-4">
142
+ <h3 class="text-yellow-400 font-bold text-xl">📖 Información General</h3>
143
+ <p class="text-white">Identificado por nuestro modelo de IA entrenado en el conjunto de datos Oxford 102 Flowers.</p>
144
+ <div class="grid grid-cols-2 gap-4 mt-4">
145
+ <div class="text-white">
146
+ <h4 class="font-semibold">🌺 Características</h4>
147
+ <ul class="list-disc ml-5">
148
+ <li>Estructuras reproductivas de la planta</li>
149
+ <li>Varios colores y formas</li>
150
+ <li>Evolucionadas para atraer polinizadores</li>
151
+ </ul>
152
+ </div>
153
+ <div class="text-white">
154
+ <h4 class="font-semibold">🎯 Cuidados Básicos</h4>
155
+ <ul class="list-disc ml-5">
156
+ <li>Buena iluminación según la especie</li>
157
+ <li>Riego regular sin exceso</li>
158
+ <li>Temperatura estable</li>
159
+ <li>Fertilización adecuada</li>
160
+ </ul>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ """
166
+
167
+ # ===== LÓGICA DE PREDICCIÓN =====
168
+ def predict(image):
169
+ if not image:
170
+ return "No se cargó ninguna imagen", "0%", """
171
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
172
+ <h3 class="text-xl font-bold">⚠️ Imagen requerida</h3>
173
+ <p>Por favor, carga una imagen de una flor para iniciar la identificación.</p>
174
+ </div>
175
+ """
176
+ if not MODEL_LOADED:
177
+ return "Error en el modelo", "0%", """
178
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
179
+ <h3 class="text-xl font-bold">🚫 Modelo no disponible</h3>
180
+ <p>No se pudo cargar el modelo de clasificación. Verifica los archivos del modelo.</p>
181
+ </div>
182
+ """
183
+ try:
184
+ img_array = preprocess_image(image)
185
+ preds = model.predict(img_array)
186
+ class_idx = np.argmax(preds[0])
187
+ confidence = preds[0][class_idx]
188
+ label_name = labels[class_idx]
189
+ flower_details = get_flower_info_from_plantnet(label_name, img_array)
190
+ return label_name, f"{confidence:.2%}", flower_details
191
+ except Exception as e:
192
+ return "Error", "0%", f"""
193
+ <div class="bg-red-600 text-white rounded-2xl p-5 m-[15px_0]">
194
+ <h3 class="text-xl font-bold">❌ Error de predicción</h3>
195
+ <p>Error durante el procesamiento: {str(e)}</p>
196
+ </div>
197
+ """
198
+
199
+ # ===== CSS PARA EL FONDO DE LA APLICACIÓN =====
200
+ custom_css = """
201
+ .gradio-container {
202
+ background: #FFFFFF;
203
+ min-height: 100vh;
204
+ }
205
+ """
206
+
207
+ # ===== JAVASCRIPT PARA OPTIMIZACIÓN DE CÁMARA =====
208
+ camera_js_improved = """
209
+ <script>
210
+ function initCameraOptimization() {
211
+ function ensureButtonsVisible() {
212
+ document.querySelectorAll('[data-testid="image"]').forEach(container => {
213
+ container.querySelectorAll('button').forEach(button => {
214
+ button.style.display = 'flex';
215
+ button.style.visibility = 'visible';
216
+ button.style.opacity = '1';
217
+ button.style.zIndex = '999';
218
+ });
219
+ });
220
+ }
221
+ ensureButtonsVisible();
222
+ setInterval(ensureButtonsVisible, 5000);
223
+ }
224
+ if (document.readyState === 'loading') {
225
+ document.addEventListener('DOMContentLoaded', initCameraOptimization);
226
+ } else {
227
+ initCameraOptimization();
228
+ }
229
+ </script>
230
+ """
231
+
232
+ # ===== APLICACIÓN PRINCIPAL =====
233
+ load_model()
234
+ img3_b64 = image_to_base64("img3.png")
235
+ img2_b64 = image_to_base64("img2.png")
236
+
237
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="🌸 Flower ") as demo:
238
+ header_html = f'''
239
+ <div style="background: rgba(37, 58, 105); border-radius: 16px; padding: 16px; margin-bottom: 24px; border: 1px solid #e5e7eb; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); max-width: 1024px; margin-left: auto; margin-right: auto;">
240
+ <div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
241
+ {'<div style="flex-shrink: 0; width: 150px; height: 150px;"><img src="data:image/png;base64,' + img3_b64 + '" alt="Logo" style="width: 100%; height: 100%; object-fit: contain; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"></div>' if img3_b64 else '<div style="width: 80px; height: 80px;"></div>'}
242
+ <div style="text-align: center;">
243
+ <h1 style="color: #FFCC00; font-size: 24px; font-weight: bold; margin-bottom: 4px;">IDENTIFICADOR DE FLORES</h1>
244
+ <p style="color: #FFFFFF; font-weight: 500; font-size: 14px; margin-bottom: 4px;">Identifica cualquier flor en cuestión de segundos</p>
245
+ <p style="color: #22c55e; font-size: 12px;">Oxford 102 Flowers + PlantNet</p>
246
+ </div>
247
+ {'<div style="flex-shrink: 0; width: 150px; height: 150px;"><img src="data:image/png;base64,' + img2_b64 + '" alt="Logo" style="width: 100%; height: 100%; object-fit: contain; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"></div>' if img2_b64 else '<div style="width: 48px; height: 48px;"></div>'}
248
+ </div>
249
+ </div>
250
+ '''
251
+ gr.HTML(header_html)
252
+
253
+ with gr.Row():
254
+ with gr.Column(scale=1):
255
+ image_input = gr.Image(type="pil", label="📷 Cargar Imagen de Flor", height=350, sources=["upload", "webcam", "clipboard"])
256
+ predict_btn = gr.Button("🔍 Identificar Flor", variant="primary")
257
+ gr.HTML(f'<div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]"><h3 class="text-yellow-400 font-bold text-xl">📊 Estado del Sistema</h3><p class="text-white">Modelo: {"✅ Activo" if MODEL_LOADED else "❌ Error"}</p><p class="text-white">Clases: {len(labels)}</p></div>')
258
+
259
+ with gr.Column(scale=1):
260
+ result_label = gr.Textbox(label="🌼 Flor Identificada", interactive=False, placeholder="El nombre de la flor aparecerá aquí...")
261
+ result_conf = gr.Textbox(label="📊 Confianza", interactive=False, placeholder="El nivel de confianza aparecerá aquí...")
262
+ flower_info_output = gr.HTML(value='<div class="bg-[rgba(255,255,255,0.1)] border-2 border-[rgba(255,165,0,0.3)] rounded-2xl p-5 m-[15px_0] shadow-[0_8px_32px_rgba(0,0,0,0.2)]"><h3 class="text-yellow-400 font-bold text-xl">🌸 ¡Bienvenido!</h3><p class="text-white">Carga una imagen de una flor para iniciar la identificación.</p></div>')
263
+
264
+ predict_btn.click(fn=predict, inputs=image_input, outputs=[result_label, result_conf, flower_info_output])
265
+ gr.HTML(camera_js_improved)
266
+
267
+ if __name__ == "__main__":
268
+ demo.launch(share=False)
clases_orden_oxford.json ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pink_primrose": 0,
3
+ "hard_leaved_pocket_orchid": 1,
4
+ "canterbury_bells": 2,
5
+ "sweet_pea": 3,
6
+ "english_marigold": 4,
7
+ "tiger_lily": 5,
8
+ "moon_orchid": 6,
9
+ "bird_of_paradise": 7,
10
+ "monkshood": 8,
11
+ "globe_thistle": 9,
12
+ "snapdragon": 10,
13
+ "colt's_foot": 11,
14
+ "king_protea": 12,
15
+ "spear_thistle": 13,
16
+ "yellow_iris": 14,
17
+ "globe_flower": 15,
18
+ "purple_coneflower": 16,
19
+ "peruvian_lily": 17,
20
+ "balloon_flower": 18,
21
+ "giant_white_arum_lily": 19,
22
+ "fire_lily": 20,
23
+ "pincushion_flower": 21,
24
+ "fritillary": 22,
25
+ "red_ginger": 23,
26
+ "grape_hyacinth": 24,
27
+ "corn_poppy": 25,
28
+ "prince_of_wales_feathers": 26,
29
+ "stemless_gentian": 27,
30
+ "artichoke": 28,
31
+ "sweet_william": 29,
32
+ "carnation": 30,
33
+ "garden_phlox": 31,
34
+ "love_in_the_mist": 32,
35
+ "mexican_aster": 33,
36
+ "alpine_sea_holly": 34,
37
+ "ruby_lipped_cattleya": 35,
38
+ "cape_flower": 36,
39
+ "great_masterwort": 37,
40
+ "siam_tulip": 38,
41
+ "lenten_rose": 39,
42
+ "barberton_daisy": 40,
43
+ "daffodil": 41,
44
+ "sword_lily": 42,
45
+ "poinsettia": 43,
46
+ "bolero_deep_blue": 44,
47
+ "wallflower": 45,
48
+ "marigold": 46,
49
+ "buttercup": 47,
50
+ "oxeye_daisy": 48,
51
+ "common_dandelion": 49,
52
+ "petunia": 50,
53
+ "wild_pansy": 51,
54
+ "primula": 52,
55
+ "sunflower": 53,
56
+ "pelargonium": 54,
57
+ "bishop_of_llandaff": 55,
58
+ "gaura": 56,
59
+ "geranium": 57,
60
+ "orange_dahlia": 58,
61
+ "pink_yellow_dahlia": 59,
62
+ "cautleya_spicata": 60,
63
+ "japanese_anemone": 61,
64
+ "black_eyed_susan": 62,
65
+ "silverbush": 63,
66
+ "californian_poppy": 64,
67
+ "osteospermum": 65,
68
+ "spring_crocus": 66,
69
+ "bearded_iris": 67,
70
+ "windflower": 68,
71
+ "tree_poppy": 69,
72
+ "gazania": 70,
73
+ "azalea": 71,
74
+ "water_lily": 72,
75
+ "rose": 73,
76
+ "thorn_apple": 74,
77
+ "morning_glory": 75,
78
+ "passion_flower": 76,
79
+ "lotus": 77,
80
+ "toad_lily": 78,
81
+ "anthurium": 79,
82
+ "frangipani": 80,
83
+ "clematis": 81,
84
+ "hibiscus": 82,
85
+ "columbine": 83,
86
+ "desert_rose": 84,
87
+ "tree_mallow": 85,
88
+ "magnolia": 86,
89
+ "cyclamen": 87,
90
+ "watercress": 88,
91
+ "canna_lily": 89,
92
+ "hippeastrum": 90,
93
+ "bee_balm": 91,
94
+ "ball_moss": 92,
95
+ "foxglove": 93,
96
+ "bougainvillea": 94,
97
+ "camellia": 95,
98
+ "mallow": 96,
99
+ "mexican_petunia": 97,
100
+ "bromelia": 98,
101
+ "blanket_flower": 99,
102
+ "trumpet_creeper": 100,
103
+ "blackberry_lily": 101
104
+ }
flores_modelo (2).h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab59a8c20162846def8e70234e6c01cfe8a99389b4b61d5b114b4286421a8e74
3
+ size 11136704
img2.png ADDED
img3.png ADDED

Git LFS Details

  • SHA256: c925a409ed5a03585ab8ea9c18bac0ec32fccaea104ed598f89ad85743252276
  • Pointer size: 131 Bytes
  • Size of remote file: 201 kB
package-lock.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "demo-clasificador-flores",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }