diff --git a/__pycache__/config_manager.cpython-310.pyc b/__pycache__/config_manager.cpython-310.pyc index 6da376a..88e9b57 100644 Binary files a/__pycache__/config_manager.cpython-310.pyc and b/__pycache__/config_manager.cpython-310.pyc differ diff --git a/backend/script_groups/esquema.json b/backend/script_groups/esquema.json index 16cbb07..54d842d 100644 --- a/backend/script_groups/esquema.json +++ b/backend/script_groups/esquema.json @@ -1,20 +1,20 @@ { + "type": "object", "properties": { "batch_size": { - "description": "N\u00c3\u00bamero de elementos a procesar por lote", + "type": "number", "title": "Tama\u00c3\u00b1o de Lote", - "type": "number" + "description": "N\u00c3\u00bamero de elementos a procesar por lote" }, "input_dir": { - "description": "Ruta al directorio de archivos de entrada", + "type": "string", "title": "Directorio de Entrada", - "type": "string" + "description": "Ruta al directorio de archivos de entrada" }, "output_dir": { - "description": "Ruta al directorio para archivos generados", + "type": "string", "title": "Directorio de Salida", - "type": "string" + "description": "Ruta al directorio para archivos generados" } - }, - "type": "object" + } } \ No newline at end of file diff --git a/backend/script_groups/example_group/description.json b/backend/script_groups/example_group/description.json new file mode 100644 index 0000000..0e0f8c1 --- /dev/null +++ b/backend/script_groups/example_group/description.json @@ -0,0 +1,6 @@ +{ + "name": "Grupo de Ejemplo", + "description": "Scripts de demostración que muestran las funcionalidades básicas del sistema", + "version": "1.0", + "author": "Admin" +} diff --git a/backend/script_groups/example_group/schema.json b/backend/script_groups/example_group/schema.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/backend/script_groups/example_group/schema.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/config_manager.py b/config_manager.py index 542ad50..8a943de 100644 --- a/config_manager.py +++ b/config_manager.py @@ -66,13 +66,36 @@ class ConfigurationManager: return {"status": "success", "path": path} - def get_script_groups(self) -> List[str]: - """Returns list of available script groups.""" - return [ - d - for d in os.listdir(self.script_groups_path) - if os.path.isdir(os.path.join(self.script_groups_path, d)) - ] + def get_script_groups(self) -> List[Dict[str, Any]]: + """Returns list of available script groups with their descriptions.""" + groups = [] + for d in os.listdir(self.script_groups_path): + group_path = os.path.join(self.script_groups_path, d) + if os.path.isdir(group_path): + description = self._get_group_description(group_path) + groups.append( + { + "id": d, + "name": description.get("name", d), + "description": description.get( + "description", "Sin descripción" + ), + "version": description.get("version", "1.0"), + "author": description.get("author", "Unknown"), + } + ) + return groups + + def _get_group_description(self, group_path: str) -> Dict[str, Any]: + """Get description for a script group.""" + description_file = os.path.join(group_path, "description.json") + try: + if os.path.exists(description_file): + with open(description_file, "r", encoding="utf-8") as f: + return json.load(f) + except Exception as e: + print(f"Error reading group description: {e}") + return {} def get_config(self, level: str, group: str = None) -> Dict[str, Any]: """Get configuration for specified level.""" @@ -93,27 +116,159 @@ class ConfigurationManager: def get_schema(self, level: str, group: str = None) -> Dict[str, Any]: """Get schema for specified level.""" - # Clean level parameter (remove -form suffix if present) - level = level.split("-")[0] - try: + # Clean level parameter + level = str(level).split("-")[0] + + # Determine schema path based on level if level == "1": path = os.path.join(self.data_path, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.data_path, "schema.json") elif level == "2": - path = os.path.join(self.script_groups_path, "esquema.json") + path = os.path.join(self.script_groups_path, group, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.script_groups_path, group, "schema.json") elif level == "3": if not group: - return {} # Return empty schema if no group is specified + return {"type": "object", "properties": {}} path = os.path.join(self.script_groups_path, group, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.script_groups_path, group, "schema.json") else: - return {} # Return empty schema for invalid levels + return {"type": "object", "properties": {}} - with open(path, "r") as f: - return json.load(f) - except FileNotFoundError: - return {} # Return empty schema if file doesn't exist - except json.JSONDecodeError: - return {} # Return empty schema if file is invalid JSON + # Read existing schema from whichever file exists + if os.path.exists(path): + with open(path, "r", encoding="utf-8") as f: + schema = json.load(f) + return ( + schema + if isinstance(schema, dict) + else {"type": "object", "properties": {}} + ) + + # Create default schema if no file exists + default_schema = {"type": "object", "properties": {}} + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "w", encoding="utf-8") as f: + json.dump(default_schema, f, indent=2) + return default_schema + + except Exception as e: + print(f"Error loading schema: {str(e)}") + return {"type": "object", "properties": {}} + + def update_schema( + self, level: str, data: Dict[str, Any], group: str = None + ) -> Dict[str, str]: + """Update schema for specified level and clean corresponding config.""" + try: + # Determinar rutas de schema y config + if level == "1": + schema_path = os.path.join(self.data_path, "esquema.json") + config_path = os.path.join(self.data_path, "data.json") + elif level == "2": + schema_path = os.path.join( + self.script_groups_path, group, "esquema.json" + ) + config_path = os.path.join(self.script_groups_path, group, "data.json") + elif level == "3": + if not group: + return { + "status": "error", + "message": "Group is required for level 3", + } + schema_path = os.path.join( + self.script_groups_path, group, "esquema.json" + ) + config_path = ( + os.path.join(self.working_directory, "data.json") + if self.working_directory + else None + ) + else: + return {"status": "error", "message": "Invalid level"} + + # Ensure directory exists + os.makedirs(os.path.dirname(schema_path), exist_ok=True) + + # Validate schema structure + if ( + not isinstance(data, dict) + or "type" not in data + or "properties" not in data + ): + data = { + "type": "object", + "properties": data if isinstance(data, dict) else {}, + } + + # Write schema + with open(schema_path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + # Clean corresponding config file + self._clean_config_for_schema(config_path, data) + + return {"status": "success"} + + except Exception as e: + print(f"Error updating schema: {str(e)}") + return {"status": "error", "message": str(e)} + + def _clean_config_for_schema( + self, config_path: str, schema: Dict[str, Any] + ) -> None: + """Clean configuration file to match schema structure.""" + if not config_path or not os.path.exists(config_path): + return + + try: + # Cargar configuración actual + with open(config_path, "r", encoding="utf-8") as f: + config = json.load(f) + + # Limpiar configuración recursivamente + cleaned_config = self._clean_object_against_schema(config, schema) + + # Guardar configuración limpia + with open(config_path, "w", encoding="utf-8") as f: + json.dump(cleaned_config, f, indent=2, ensure_ascii=False) + + except Exception as e: + print(f"Error cleaning config: {str(e)}") + + def _clean_object_against_schema( + self, data: Dict[str, Any], schema: Dict[str, Any] + ) -> Dict[str, Any]: + """Recursively clean object to match schema structure.""" + if not isinstance(data, dict) or not isinstance(schema, dict): + return {} + + result = {} + schema_props = schema.get("properties", {}) + + for key, value in data.items(): + # Solo mantener campos que existen en el schema + if key in schema_props: + prop_schema = schema_props[key] + + # Si es un objeto anidado, limpiar recursivamente + if prop_schema.get("type") == "object": + result[key] = self._clean_object_against_schema(value, prop_schema) + # Si es un enum, verificar que el valor sea válido + elif "enum" in prop_schema: + if value in prop_schema["enum"]: + result[key] = value + # Para otros tipos, mantener el valor + else: + result[key] = value + + return result def update_config( self, level: str, data: Dict[str, Any], group: str = None @@ -132,20 +287,6 @@ class ConfigurationManager: with open(path, "w") as f: json.dump(data, f, indent=2) - def update_schema( - self, level: str, data: Dict[str, Any], group: str = None - ) -> None: - """Update schema for specified level.""" - if level == "1": - path = os.path.join(self.data_path, "esquema.json") - elif level == "2": - path = os.path.join(self.script_groups_path, "esquema.json") - elif level == "3": - path = os.path.join(self.script_groups_path, group, "esquema.json") - - with open(path, "w") as f: - json.dump(data, f, indent=2) - def list_scripts(self, group: str) -> List[Dict[str, str]]: """List all scripts in a group with their descriptions.""" try: diff --git a/data/data.json b/data/data.json index e599297..245a1ab 100644 --- a/data/data.json +++ b/data/data.json @@ -1,6 +1,4 @@ { "api_key": "your-api-key-here", - "model": "gpt-3.5-turbo", - "max_tokens": 1000, - "temperature": 0.7 -} + "model": "gpt-3.5-turbo" +} \ No newline at end of file diff --git a/data/esquema.json b/data/esquema.json index 88b52aa..5d04917 100644 --- a/data/esquema.json +++ b/data/esquema.json @@ -1,32 +1,20 @@ { + "type": "object", "properties": { "api_key": { - "description": "Tu clave de API para servicios externos", + "type": "string", "title": "API Key", - "type": "string" - }, - "max_tokens": { - "description": "N\u00c3\u00bamero m\u00c3\u00a1ximo de tokens por respuesta", - "title": "Tokens M\u00c3\u00a1ximos", - "type": "number" + "description": "Tu clave de API para servicios externos" }, "model": { + "type": "string", + "title": "Modelo LLM", "description": "Modelo de lenguaje a utilizar", "enum": [ "gpt-3.5-turbo", "gpt-4", "claude-v1" - ], - "title": "Modelo LLM", - "type": "string" - }, - "temperature": { - "description": "Creatividad de las respuestas (0-1)", - "maximum": 1, - "minimum": 0, - "title": "Temperatura", - "type": "number" + ] } - }, - "type": "object" + } } \ No newline at end of file diff --git a/data/log.txt b/data/log.txt index cac062f..7119ef2 100644 --- a/data/log.txt +++ b/data/log.txt @@ -5,9 +5,7 @@ Iniciando ejecución de x1.py... Configuraciones cargadas: Nivel 1: { "api_key": "your-api-key-here", - "model": "gpt-3.5-turbo", - "max_tokens": 1000, - "temperature": 0.7 + "model": "gpt-3.5-turbo" } Nivel 2: { "input_dir": "D:/Datos/Entrada", diff --git a/data/schema.json b/data/schema.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/data/schema.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 81639c4..d8dd941 100644 --- a/templates/index.html +++ b/templates/index.html @@ -92,7 +92,7 @@ // Form rendering functionality async function renderForm(containerId, data) { - console.log(`Rendering form for ${containerId}`); // Debug line + console.log(`Rendering form for ${containerId} with data:`, data); // Debug line const container = document.getElementById(containerId); const level = containerId.replace('level', '').split('-')[0]; @@ -101,13 +101,14 @@ const schema = await schemaResponse.json(); console.log(`Schema for level ${level}:`, schema); // Debug line - if (Object.keys(schema).length === 0) { + if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) { container.innerHTML = '
No hay esquema definido para este nivel.
'; - } else { - const formHtml = generateFormFields(schema, data, '', level); - console.log(`Generated HTML for ${containerId}:`, formHtml.substring(0, 100) + '...'); // Debug line - container.innerHTML = formHtml; + return; } + + const formHtml = generateFormFields(schema, data || {}, '', level); + console.log(`Generated HTML for ${containerId}:`, formHtml.substring(0, 100) + '...'); // Debug line + container.innerHTML = formHtml; } catch (error) { console.error(`Error rendering form ${containerId}:`, error); container.innerHTML = 'Error cargando el esquema.
'; @@ -115,10 +116,18 @@ } function generateFormFields(schema, data, prefix, level) { + console.log('Generating fields with data:', { schema, data, prefix, level }); // Debug line let html = ''; + + if (!schema.properties) { + console.warn('Schema has no properties'); + return html; + } + for (const [key, def] of Object.entries(schema.properties)) { const fullKey = prefix ? `${prefix}.${key}` : key; const value = getValue(data, fullKey); + console.log(`Field ${fullKey}:`, { definition: def, value: value }); // Debug line html += `