dfernandezl12's picture
Upload 8 files
57c87d3 verified
Raw
History Blame Contribute Delete
3.1 kB
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
import numpy as np
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import load_img, img_to_array
from PIL import Image
import io
import tensorflow as tf
from tensorflow.keras.layers import Dense
app = FastAPI(title="Clasificador de Vehículos")
class CompatDense(Dense):
def __init__(self, *Args, quantization_config=None, **kwargs):
# Eliminamos el problema de discusión y al padre
kwargs.pop('quantization_config', None)
super().__init__(*Args, **kwargs)
# Cargar el modelo entrenado (arquitectura + pesos incluidos en modelo.h5)
model = load_model(
'modelo/modelo.h5',
custom_objects={'Dense': CompatDense}
)
# Etiquetas de las clases, en el orden que usó ImageDataGenerator (alfabético)
CLASS_NAMES = ['airplane', 'car', 'ship'] # 0: aéreo, 1: terrestre, 2: marítimo
def preprocess_image(image: Image.Image):
"""
Preprocesa la imagen para que coincida con el entrenamiento.
"""
image = image.resize((150, 150)) # tamaño usado en el notebook
img_array = img_to_array(image) # convierte a array (150,150,3)
img_array = img_array / 255.0 # normalización (rescale=1./255)
img_array = np.expand_dims(img_array, axis=0) # añade dimensión batch
return img_array
@app.post("/predict")
async def predict(file: UploadFile = File(...)):
"""
Recibe una imagen y devuelve la clase predicha con su confianza.
"""
# Leer el contenido del archivo
contents = await file.read()
try:
# Convertir a imagen RGB
image = Image.open(io.BytesIO(contents)).convert('RGB')
except Exception:
return JSONResponse(
content={"error": "No se pudo leer la imagen. Asegúrate de enviar un archivo válido."},
status_code=400
)
# Preprocesar y predecir
processed = preprocess_image(image)
predictions = model.predict(processed)[0] # array de 3 probabilidades
predicted_idx = np.argmax(predictions)
label = CLASS_NAMES[predicted_idx]
confidence = float(predictions[predicted_idx])
# Mapeo legible para el usuario
label_es = {"airplane": "Aéreo (Avión)", "car": "Terrestre (Coche)", "ship": "Marítimo (Barco)"}
return {
"prediccion": label_es[label],
"confianza": round(confidence, 4),
"probabilidades": {
"airplane": round(float(predictions[0]), 4),
"car": round(float(predictions[1]), 4),
"ship": round(float(predictions[2]), 4)
}
}
app.mount("/static", StaticFiles(directory="static"), name="static")
# Endpoint de bienvenida (opcional)
@app.get("/")
def read_index():
return FileResponse("static/index.html")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)