From 66f21181e32af85e8ad3cc4b9ec97e9d084b2226 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 14 Apr 2026 11:07:12 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20arreglar=20mensajes=20de=20error=20cuand?= =?UTF-8?q?o=20inputs=20vac=C3=ADos=20en=20paso2=20(proceso)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/models/docit2mf_models.py | 18 ++++---- frontend/src/pages/DocEditor.jsx | 60 ++++++++++++++++++--------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/backend/api/models/docit2mf_models.py b/backend/api/models/docit2mf_models.py index a9a20d6..8464a9a 100644 --- a/backend/api/models/docit2mf_models.py +++ b/backend/api/models/docit2mf_models.py @@ -1,6 +1,6 @@ # models/docit2mf_models.py -from pydantic import BaseModel, field_validator +from pydantic import BaseModel, Field, field_validator, ValidationInfo from typing import List, Tuple, Union @@ -9,8 +9,8 @@ BlankCardInput = Union[int, Tuple[int, int], List[int]] class DoCIT2MFRequest(BaseModel): term: str - core: Tuple[float, float] - support: Tuple[float, float] + core: tuple[float, float] = Field(..., description="Núcleo del conjunto difuso: [a, b]") + support: tuple[float, float] = Field(..., description="Soporte del conjunto difuso: [c, d]") left_nodes_x: List[float] left_blank_cards: List[BlankCardInput] @@ -28,20 +28,20 @@ class DoCIT2MFRequest(BaseModel): def core_valid(cls, v): a, b = v if a > b: - raise ValueError("El núcleo debe cumplir a <= b.") + raise ValueError("el 'Inicio del Núcleo' debe ser menor o igual al 'Fin del Núcleo'.") return v @field_validator("support") - def support_valid(cls, v, info): + def support_valid(cls, v, info: ValidationInfo): c, d = v - if c >= d: - raise ValueError("El soporte debe cumplir c <= d.") + if c > d: + raise ValueError("el 'Inicio del Soporte' debe ser menor o igual al 'Fin del Soporte'.") core = info.data.get("core") if core: a, b = core - if not (c <= a <= b <= d): - raise ValueError("El núcleo debe estar dentro del soporte.") + if not (c <= a and b <= d): + raise ValueError("los valores del 'Núcleo' deben estar estrictamente dentro del 'Soporte'.") return v @field_validator("left_blank_cards", "right_blank_cards") diff --git a/frontend/src/pages/DocEditor.jsx b/frontend/src/pages/DocEditor.jsx index 1ea2b5b..edeb2ba 100644 --- a/frontend/src/pages/DocEditor.jsx +++ b/frontend/src/pages/DocEditor.jsx @@ -162,29 +162,51 @@ export default function DocEditor() { setFinalResult(result); setStep(3); } catch (error) { - console.error("Error capturado:", error); - let friendlyMessage = "Ocurrió un error de validación."; + console.error("Error capturado detallado:", error); + let friendlyMessage = "Ocurrió un error de validación al generar la gráfica."; - if (Array.isArray(error)) { - friendlyMessage = error.map(err => { - let msg = err.msg.replace("Value error, ", ""); - - // Traducción de mensajes del backend - msg = msg.replace("a < b", "el 'Inicio del Soporte' no puede ser mayor que el 'Inicio del Núcleo'"); - msg = msg.replace("b <= c", "el 'Inicio del Núcleo' no puede ser mayor que el 'Fin del Núcleo'"); - msg = msg.replace("c < d", "el 'Fin del Núcleo' no puede ser mayor que el 'Fin del Soporte'"); - msg = msg.replace("El soporte debe cumplir", "Revisa los valores:"); - msg = msg.replace("El núcleo debe cumplir", "Revisa los valores:"); + // 1. BUSCADOR DE ERRORES: Extraemos el detalle venga como venga (Axios, Pydantic, o genérico) + let details = error; + if (error.response && error.response.data && error.response.data.detail) { + details = error.response.data.detail; // Array de Pydantic + } else if (error.detail) { + details = error.detail; + } - if (err.loc && err.loc.includes("levels")) { - const levelIndex = err.loc[err.loc.indexOf("levels") + 1]; - const termName = scaleKeys[levelIndex] || `Nivel ${Number(levelIndex) + 1}`; - return `• En la etiqueta "${termName}": ${msg}`; + // 2. Si logramos extraer el Array de Pydantic + if (Array.isArray(details)) { + friendlyMessage = details.map(err => { + // Limpiamos el texto que ensucia Pydantic ("Value error, ") + const cleanMsg = err.msg ? err.msg.replace("Value error, ", "") : "Valor incorrecto"; + + // Buscamos en qué etiqueta falló usando err.loc + if (err.loc) { + const levelIndexPos = err.loc.indexOf("levels"); + if (levelIndexPos !== -1 && err.loc.length > levelIndexPos + 1) { + const levelIndex = err.loc[levelIndexPos + 1]; + const termName = scaleKeys[levelIndex] || `Nivel ${Number(levelIndex) + 1}`; + return `• En la etiqueta "${termName}": ${cleanMsg}`; + } + // Formato alternativo de Pydantic v2 + if (typeof err.loc[1] === 'number') { + const termName = scaleKeys[err.loc[1]] || `Nivel ${err.loc[1] + 1}`; + return `• En la etiqueta "${termName}": ${cleanMsg}`; + } } - return `• ${msg}`; + return `• ${cleanMsg}`; }).join("\n"); - } else if (typeof error === 'string') { - friendlyMessage = error; + } + // 3. Si el backend nos mandó un simple string + else if (typeof details === 'string') { + friendlyMessage = details; + } + // 4. Si es un error genérico (Axios de bajo nivel) + else if (error.message) { + if (error.message.includes("422")) { + friendlyMessage = "Revisa los datos: asegúrate de que el 'Núcleo' esté dentro del 'Soporte' y que c <= d."; + } else { + friendlyMessage = error.message; + } } setSubmitError(friendlyMessage);