Spaces:
Runtime error
Runtime error
| import os | |
| import numpy as np | |
| import tensorflow as tf | |
| from tensorflow.keras import layers, models | |
| from flask import Flask, request, jsonify, render_template | |
| from PIL import Image | |
| import io | |
| from datasets import load_dataset | |
| # ------------------------------ | |
| # Configuración | |
| # ------------------------------ | |
| MODEL_PATH = "modelo_sexo.keras" # Cambiado para evitar conflictos con el viejo | |
| IMG_SIZE = (64, 64) | |
| def build_model(): | |
| model = models.Sequential([ | |
| layers.Conv2D(32, (3, 3), activation='relu', input_shape=(64, 64, 3)), | |
| layers.MaxPooling2D((2, 2)), | |
| layers.Conv2D(64, (3, 3), activation='relu'), | |
| layers.Flatten(), | |
| layers.Dense(64, activation='relu'), | |
| layers.Dense(1, activation='sigmoid') # 1 = mujer, 0 = hombre | |
| ]) | |
| model.compile(optimizer='adam', | |
| loss='binary_crossentropy', | |
| metrics=['accuracy']) | |
| return model | |
| def train_and_save_model(): | |
| print("Cargando dataset FairFace...") | |
| ds = load_dataset("HuggingFaceM4/FairFace", "0.25") | |
| # Usamos todo el dataset de entrenamiento disponible | |
| ds_train = ds['train'] | |
| images = [] | |
| labels = [] | |
| print("Procesando imágenes para clasificación de género...") | |
| for item in ds_train: | |
| img = item['image'].convert('RGB').resize(IMG_SIZE) | |
| images.append(np.array(img) / 255.0) | |
| # En FairFace: 0 corresponde a 'Male' (Hombre) y 1 a 'Female' (Mujer) | |
| labels.append(1.0 if item['gender'] == 1 else 0.0) | |
| X = np.array(images) | |
| y = np.array(labels) | |
| print(f"Datos cargados: {len(X)} imágenes (mujeres: {sum(y)}, hombres: {len(y)-sum(y)})") | |
| # Entrenar modelo | |
| model = build_model() | |
| print("Entrenando clasificador de género...") | |
| model.fit(X, y, epochs=7, batch_size=64, validation_split=0.2, verbose=1) | |
| # Guardar el nuevo modelo | |
| model.save(MODEL_PATH) | |
| print(f"Modelo guardado como {MODEL_PATH}") | |
| return model | |
| # Cargar modelo o entrenar si no existe | |
| def load_or_train_model(): | |
| if os.path.exists(MODEL_PATH): | |
| try: | |
| model = tf.keras.models.load_model(MODEL_PATH) | |
| print("✅ Modelo de género cargado desde disco correctamente") | |
| return model | |
| except Exception as e: | |
| print(f"⚠️ Error al cargar el modelo: {e}") | |
| print("Entrenando uno nuevo...") | |
| return train_and_save_model() | |
| else: | |
| print("Modelo no encontrado. Entrenando desde cero...") | |
| return train_and_save_model() | |
| # Inicializar el modelo global | |
| model = load_or_train_model() | |
| # ------------------------------ | |
| # Aplicación Flask | |
| # ------------------------------ | |
| app = Flask(__name__) | |
| def predecir_sexo(imagen_bytes): | |
| img = Image.open(io.BytesIO(imagen_bytes)).convert('RGB') | |
| img = img.resize(IMG_SIZE) | |
| img_array = np.array(img) / 255.0 | |
| img_array = np.expand_dims(img_array, axis=0) | |
| prediccion = model.predict(img_array, verbose=0)[0][0] | |
| return "mujer" if prediccion >= 0.5 else "hombre" | |
| def index(): | |
| return render_template('index.html') | |
| def predict(): | |
| if 'image' not in request.files: | |
| return jsonify({'error': 'No se encontró ninguna imagen'}), 400 | |
| file = request.files['image'] | |
| if file.filename == '': | |
| return jsonify({'error': 'Nombre de archivo vacío'}), 400 | |
| try: | |
| imagen_bytes = file.read() | |
| # 1. Obtenemos el valor numérico puro de la predicción | |
| img = Image.open(io.BytesIO(imagen_bytes)).convert('RGB') | |
| img = img.resize(IMG_SIZE) | |
| img_array = np.array(img) / 255.0 | |
| img_array = np.expand_dims(img_array, axis=0) | |
| # Guardamos la predicción como un float para poder operar con ella | |
| prediccion_raw = float(model.predict(img_array, verbose=0)[0][0]) | |
| # 2. Calculamos la clase y el porcentaje de confianza | |
| if prediccion_raw >= 0.5: | |
| genero = "mujer" | |
| # Si es mujer, la confianza es directamente el valor predicho (ej: 0.90 -> 90%) | |
| confianza = prediccion_raw * 100 | |
| else: | |
| genero = "hombre" | |
| # Si es hombre, la confianza es lo que le falta para 1 (ej: 0.10 predicho -> 90% seguro de que es hombre) | |
| confianza = (1.0 - prediccion_raw) * 100 | |
| # 3. Devolvemos el JSON con ambos datos, formateando la confianza a 2 decimales | |
| return jsonify({ | |
| 'genero': genero, | |
| 'confianza': f"{confianza:.2f}%" | |
| }) | |
| except Exception as e: | |
| return jsonify({'error': str(e)}), 500 | |
| if __name__ == '__main__': | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(host='0.0.0.0', port=port) |