diff --git a/__pycache__/config_manager.cpython-310.pyc b/__pycache__/config_manager.cpython-310.pyc index f48bd70..6da376a 100644 Binary files a/__pycache__/config_manager.cpython-310.pyc and b/__pycache__/config_manager.cpython-310.pyc differ diff --git a/app.py b/app.py index 681807f..150e464 100644 --- a/app.py +++ b/app.py @@ -26,7 +26,7 @@ def handle_websocket(ws): def broadcast_message(message): - """Envía un mensaje a todas las conexiones WebSocket activas.""" + """Envía un mensaje a todas las conexiones WebSocket activas y guarda en log.""" dead_connections = set() for ws in websocket_connections: try: @@ -34,6 +34,9 @@ def broadcast_message(message): except Exception: dead_connections.add(ws) + # Guardar en archivo de log + config_manager.append_log(message) + # Limpiar conexiones muertas websocket_connections.difference_update(dead_connections) @@ -147,5 +150,14 @@ def browse_directories(): return jsonify({"status": "cancelled"}) +@app.route("/api/logs", methods=["GET", "DELETE"]) +def handle_logs(): + if request.method == "GET": + return jsonify({"logs": config_manager.read_log()}) + else: # DELETE + success = config_manager.clear_log() + return jsonify({"status": "success" if success else "error"}) + + if __name__ == "__main__": app.run(debug=True) diff --git a/config_manager.py b/config_manager.py index e58bf81..542ad50 100644 --- a/config_manager.py +++ b/config_manager.py @@ -13,6 +13,43 @@ class ConfigurationManager: self.base_path, "backend", "script_groups" ) self.working_directory = None + self.log_file = os.path.join(self.data_path, "log.txt") + self._init_log_file() + + def _init_log_file(self): + """Initialize log file if it doesn't exist""" + if not os.path.exists(self.data_path): + os.makedirs(self.data_path) + if not os.path.exists(self.log_file): + with open(self.log_file, "w", encoding="utf-8") as f: + f.write("") + + def append_log(self, message: str) -> None: + """Append a message to the log file""" + try: + with open(self.log_file, "a", encoding="utf-8") as f: + f.write(message) + except Exception as e: + print(f"Error writing to log file: {e}") + + def read_log(self) -> str: + """Read the entire log file""" + try: + with open(self.log_file, "r", encoding="utf-8") as f: + return f.read() + except Exception as e: + print(f"Error reading log file: {e}") + return "" + + def clear_log(self) -> bool: + """Clear the log file""" + try: + with open(self.log_file, "w", encoding="utf-8") as f: + f.write("") + return True + except Exception as e: + print(f"Error clearing log file: {e}") + return False def set_working_directory(self, path: str) -> Dict[str, str]: """Set and validate working directory.""" diff --git a/data/log.txt b/data/log.txt new file mode 100644 index 0000000..cac062f --- /dev/null +++ b/data/log.txt @@ -0,0 +1,30 @@ + +Iniciando ejecución de x1.py... +=== Ejecutando Script de Prueba 1 === + +Configuraciones cargadas: +Nivel 1: { + "api_key": "your-api-key-here", + "model": "gpt-3.5-turbo", + "max_tokens": 1000, + "temperature": 0.7 +} +Nivel 2: { + "input_dir": "D:/Datos/Entrada", + "output_dir": "D:/Datos/Salida", + "batch_size": 50 +} +Nivel 3: { + "project_name": "Test" +} + +Simulando procesamiento... +Progreso: 20% +Progreso: 40% +Progreso: 60% +Progreso: 80% +Progreso: 100% + +¡Proceso completado! + +Ejecución completada. diff --git a/templates/index.html b/templates/index.html index 4e3e4b4..81639c4 100644 --- a/templates/index.html +++ b/templates/index.html @@ -174,38 +174,210 @@ } async function modifySchema(level) { - const response = await fetch(`/api/schema/${level}?group=${currentGroup}`); - const schema = await response.json(); - - // Show schema editor modal - const modal = document.getElementById('schema-editor'); - modal.classList.remove('hidden'); + try { + console.log('Loading schema for level:', level); // Debug line + const response = await fetch(`/api/schema/${level}?group=${currentGroup}`); + const schema = await response.json(); + console.log('Loaded schema:', schema); // Debug line + + // Show schema editor modal + const modal = document.getElementById('schema-editor'); + modal.classList.remove('hidden'); + + // Inicializar JSON editor + const jsonEditor = document.getElementById('json-editor'); + jsonEditor.value = JSON.stringify(schema, null, 2); + + // Inicializar visual editor + const visualEditor = document.getElementById('visual-editor'); + visualEditor.innerHTML = '
' + + ''; + + // Renderizar campos existentes + renderVisualEditor(schema); + + // Guardar nivel actual + document.getElementById('schema-level').value = level; + + // Activar pestaña visual por defecto + switchEditorMode('visual'); + } catch (error) { + console.error('Error loading schema:', error); + alert('Error cargando el esquema'); + } + } + + function switchEditorMode(mode) { + const visualEditor = document.getElementById('visual-editor'); + const jsonEditor = document.getElementById('json-editor'); + const visualTab = document.getElementById('visual-tab'); + const jsonTab = document.getElementById('json-tab'); + + if (mode === 'visual') { + visualEditor.classList.remove('hidden'); + jsonEditor.classList.add('hidden'); + visualTab.classList.add('border-blue-500'); + jsonTab.classList.remove('border-blue-500'); + } else { + visualEditor.classList.add('hidden'); + jsonEditor.classList.remove('hidden'); + visualTab.classList.remove('border-blue-500'); + jsonTab.classList.add('border-blue-500'); + } + } + + function renderVisualEditor(schema) { + const container = document.getElementById('schema-fields'); + container.innerHTML = ''; + + Object.entries(schema.properties || {}).forEach(([key, field]) => { + container.appendChild(createFieldEditor(key, field)); + }); + } + + function createFieldEditor(key, field) { + const div = document.createElement('div'); + div.className = 'mb-6 p-4 border rounded schema-field'; + div.innerHTML = ` +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ ${field.enum ? ` +
+ + +
+ ` : ''} + + `; + return div; + } + + function updateFieldType(select) { + const fieldContainer = select.closest('.schema-field'); + const enumContainer = fieldContainer.querySelector('.enum-container'); + if (select.value === 'enum') { + if (!enumContainer) { + const div = document.createElement('div'); + div.className = 'enum-container mt-4'; + div.innerHTML = ` + + + `; + fieldContainer.appendChild(div); + } + } else if (enumContainer) { + enumContainer.remove(); + } + updateVisualSchema(); + } + + function removeField(button) { + const fieldContainer = button.closest('.schema-field'); + fieldContainer.remove(); + updateVisualSchema(); + } + + function createEnumEditor(enumValues) { + return ` +
+ + +
+ `; + } + + function addSchemaField() { + const container = document.getElementById('schema-fields'); + const newField = createFieldEditor(`campo_${Date.now()}`, { + type: 'string', + title: 'Nuevo Campo', + description: '' + }); + container.appendChild(newField); + } + + // Funciones de actualización del esquema visual + function updateVisualSchema() { + const fields = document.getElementById('schema-fields').children; + const schema = { + type: 'object', + properties: {} + }; + + Array.from(fields).forEach(field => { + const inputs = field.getElementsByTagName('input'); + const select = field.getElementsByTagName('select')[0]; + const key = inputs[0].value; + + schema.properties[key] = { + type: select.value === 'enum' ? 'string' : select.value, + title: inputs[1].value, + description: inputs[2].value + }; + + if (select.value === 'enum') { + const textarea = field.getElementsByTagName('textarea')[0]; + schema.properties[key].enum = textarea.value.split('\n').filter(v => v.trim()); + } + }); + document.getElementById('schema-content').value = JSON.stringify(schema, null, 2); - document.getElementById('schema-level').value = level; + return schema; } async function saveSchema() { - const level = document.getElementById('schema-level').value; - const content = document.getElementById('schema-content').value; - try { - const schema = JSON.parse(content); + const level = document.getElementById('schema-level').value; + const schema = updateVisualSchema(); + await fetch(`/api/schema/${level}?group=${currentGroup}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(schema) }); - // Refresh form const response = await fetch(`/api/config/${level}?group=${currentGroup}`); const data = await response.json(); renderForm(`level${level}-form`, data); - // Hide modal document.getElementById('schema-editor').classList.add('hidden'); } catch (e) { - alert('Invalid JSON schema: ' + e.message); + alert('Error guardando esquema: ' + e.message); } } @@ -335,14 +507,27 @@ } } - function clearLogs() { - document.getElementById('log-area').innerHTML = ''; + async function clearLogs() { + const response = await fetch('/api/logs', { method: 'DELETE' }); + const result = await response.json(); + if (result.status === 'success') { + document.getElementById('log-area').innerHTML = ''; + } + } + + async function loadStoredLogs() { + const response = await fetch('/api/logs'); + const result = await response.json(); + const logArea = document.getElementById('log-area'); + logArea.innerHTML = result.logs; + logArea.scrollTop = logArea.scrollHeight; } // Initialize on page load async function initializeApp() { try { initWebSocket(); + await loadStoredLogs(); // Cargar logs almacenados // Primero establecer el grupo actual const group = localStorage.getItem('selectedGroup'); @@ -501,7 +686,15 @@