config_manager dividido en partes para que no sea tan grande

This commit is contained in:
Miguel 2025-05-03 21:03:33 +02:00
parent d63abc971c
commit c759a756be
11 changed files with 88 additions and 1264 deletions

57
app.py
View File

@ -1,6 +1,6 @@
from flask import Flask, render_template, request, jsonify, url_for from flask import Flask, render_template, request, jsonify, url_for
from flask_sock import Sock from flask_sock import Sock
from config_manager import ConfigurationManager from lib.config_manager import ConfigurationManager
import os import os
import json # Added import import json # Added import
from datetime import datetime from datetime import datetime
@ -46,7 +46,7 @@ def broadcast_message(message):
dead_connections = set() dead_connections = set()
timestamp = datetime.now().strftime("[%H:%M:%S] ") timestamp = datetime.now().strftime("[%H:%M:%S] ")
# Si es una lista de mensajes, procesar cada uno # Normalize input to a list of messages
if isinstance(message, list): if isinstance(message, list):
messages = message messages = message
else: else:
@ -54,32 +54,32 @@ def broadcast_message(message):
messages = [line.strip() for line in message.splitlines() if line.strip()] messages = [line.strip() for line in message.splitlines() if line.strip()]
# Procesar cada mensaje # Procesar cada mensaje
for msg in messages: for raw_msg in messages:
# Limpiar timestamps duplicados al inicio del mensaje # Limpiar timestamps duplicados al inicio del mensaje
while msg.startswith("[") and "]" in msg: while raw_msg.startswith("[") and "]" in raw_msg:
try: try:
closing_bracket = msg.index("]") + 1 closing_bracket = raw_msg.index("]") + 1
if msg[1 : closing_bracket - 1].replace(":", "").isdigit(): if raw_msg[1 : closing_bracket - 1].replace(":", "").isdigit():
msg = msg[closing_bracket:].strip() raw_msg = raw_msg[closing_bracket:].strip() # Update raw_msg itself
else: else:
break break
except: except:
break break
# Añadir un único timestamp # Log the raw message using the config_manager's logger
formatted_msg = f"{timestamp}{msg}" # The logger will handle its own timestamping for the file.
config_manager.append_log(raw_msg)
# Escribir en el archivo de log # Format message with timestamp *for WebSocket broadcast*
with open(config_manager.log_file, "a", encoding="utf-8") as f: formatted_msg_for_ws = f"{timestamp}{raw_msg}"
f.write(f"{formatted_msg}\n")
# Enviar a todos los clientes WebSocket # Enviar a todos los clientes WebSocket
for ws in list(websocket_connections): for ws in list(websocket_connections):
try: try:
if ws.connected: if ws.connected: # Check if ws is still connected before sending
ws.send(f"{formatted_msg}\n") ws.send(f"{formatted_msg_for_ws}\n") # Use the correct variable name here
except Exception: except Exception:
dead_connections.add(ws) dead_connections.add(ws) # Collect dead connections
# Limpiar conexiones muertas # Limpiar conexiones muertas
websocket_connections.difference_update(dead_connections) websocket_connections.difference_update(dead_connections)
@ -205,30 +205,19 @@ def handle_logs():
@app.route("/api/group-description/<group>", methods=["GET", "POST"]) @app.route("/api/group-description/<group>", methods=["GET", "POST"])
def handle_group_description(group): def handle_group_description(group):
description_path = os.path.join(
config_manager.script_groups_path, group, "description.json"
)
if request.method == "GET": if request.method == "GET":
try: try:
with open(description_path, "r", encoding="utf-8") as f: details = config_manager.get_group_details(group)
return jsonify(json.load(f)) if "error" in details:
except FileNotFoundError: return jsonify(details), 404 # Group not found
return jsonify( return jsonify(details)
{ except Exception as e:
"name": group, return jsonify({"status": "error", "message": str(e)}), 500
"description": "Sin descripción",
"version": "1.0",
"author": "Unknown",
}
)
else: # POST else: # POST
try: try:
data = request.json data = request.json
os.makedirs(os.path.dirname(description_path), exist_ok=True) result = config_manager.update_group_description(group, data)
with open(description_path, "w", encoding="utf-8") as f: return jsonify(result)
json.dump(data, f, indent=2, ensure_ascii=False)
return jsonify({"status": "success"})
except Exception as e: except Exception as e:
return jsonify({"status": "error", "message": str(e)}), 500 return jsonify({"status": "error", "message": str(e)}), 500

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,15 @@
--- Log de Ejecución: x1_to_json.py ---
Grupo: XML Parser to SCL
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport
Inicio: 2025-05-03 20:08:18
Fin: 2025-05-03 20:08:22
Duración: 0:00:03.850097
Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) ---
Por favor, selecciona el archivo XML de entrada...
--- ERRORES (STDERR) ---
No se seleccionó ningún archivo. Saliendo.
--- FIN DEL LOG ---

View File

@ -1,9 +1,9 @@
--- Log de Ejecución: x1.py --- --- Log de Ejecución: x1.py ---
Grupo: example_group Grupo: example_group
Directorio de Trabajo: C:\Estudio Directorio de Trabajo: C:\Estudio
Inicio: 2025-05-03 17:26:22 Inicio: 2025-05-03 20:54:12
Fin: 2025-05-03 17:26:27 Fin: 2025-05-03 20:54:17
Duración: 0:00:05.167151 Duración: 0:00:05.196719
Estado: SUCCESS (Código de Salida: 0) Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) --- --- SALIDA ESTÁNDAR (STDOUT) ---

View File

@ -1,9 +1,9 @@
--- Log de Ejecución: x2.py --- --- Log de Ejecución: x2.py ---
Grupo: example_group Grupo: example_group
Directorio de Trabajo: C:\Estudio Directorio de Trabajo: C:\Estudio
Inicio: 2025-05-03 17:26:13 Inicio: 2025-05-03 20:48:23
Fin: 2025-05-03 17:26:14 Fin: 2025-05-03 20:48:27
Duración: 0:00:01.149705 Duración: 0:00:03.208350
Estado: SUCCESS (Código de Salida: 0) Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) --- --- SALIDA ESTÁNDAR (STDOUT) ---
@ -11,6 +11,10 @@ Estado: SUCCESS (Código de Salida: 0)
Iniciando análisis de datos simulado... Iniciando análisis de datos simulado...
Analizando lote 1... Analizando lote 1...
Lote 1 completado exitosamente
Analizando lote 2...
Lote 2 completado exitosamente
Analizando lote 3...
ERROR: Error simulado en el procesamiento ERROR: Error simulado en el procesamiento
El proceso se detuvo debido a un error El proceso se detuvo debido a un error

View File

@ -1,171 +0,0 @@
import os
import shutil
from pathlib import Path
import re
class ClaudeProjectOrganizer:
def __init__(self):
self.source_dir = Path.cwd()
self.claude_dir = self.source_dir / 'claude'
self.file_mapping = {}
def should_skip_directory(self, dir_name):
skip_dirs = {'.git', '__pycache__', 'venv', 'env', '.pytest_cache', '.vscode', 'claude'}
return dir_name in skip_dirs
def get_comment_prefix(self, file_extension):
"""Determina el prefijo de comentario según la extensión del archivo"""
comment_styles = {
'.py': '#',
'.js': '//',
'.css': '/*',
'.html': '<!--',
'.scss': '//',
'.less': '//',
'.tsx': '//',
'.ts': '//',
'.jsx': '//',
}
return comment_styles.get(file_extension.lower(), None)
def get_comment_suffix(self, file_extension):
"""Determina el sufijo de comentario si es necesario"""
comment_suffixes = {
'.css': ' */',
'.html': ' -->',
}
return comment_suffixes.get(file_extension.lower(), '')
def normalize_path(self, path_str: str) -> str:
"""Normaliza la ruta usando forward slashes"""
return str(path_str).replace('\\', '/')
def check_existing_path_comment(self, content: str, normalized_path: str, comment_prefix: str) -> bool:
"""Verifica si ya existe un comentario con la ruta en el archivo"""
# Escapar caracteres especiales en el prefijo de comentario para regex
escaped_prefix = re.escape(comment_prefix)
# Crear patrones para buscar tanto forward como backward slashes
forward_pattern = f"{escaped_prefix}\\s*{re.escape(normalized_path)}\\b"
backward_path = normalized_path.replace('/', '\\\\') # Doble backslash para el patrón
backward_pattern = f"{escaped_prefix}\\s*{re.escape(backward_path)}"
# Buscar en las primeras líneas del archivo
first_lines = content.split('\n')[:5]
for line in first_lines:
if (re.search(forward_pattern, line) or
re.search(backward_pattern, line)):
return True
return False
def add_path_comment(self, file_path: Path, content: str) -> str:
"""Agrega un comentario con la ruta al inicio del archivo si no existe"""
relative_path = file_path.relative_to(self.source_dir)
normalized_path = self.normalize_path(relative_path)
comment_prefix = self.get_comment_prefix(file_path.suffix)
if comment_prefix is None:
return content
comment_suffix = self.get_comment_suffix(file_path.suffix)
# Verificar si ya existe el comentario
if self.check_existing_path_comment(content, normalized_path, comment_prefix):
print(f" - Comentario de ruta ya existe en {file_path}")
return content
path_comment = f"{comment_prefix} {normalized_path}{comment_suffix}\n"
# Para archivos HTML, insertar después del doctype si existe
if file_path.suffix.lower() == '.html':
if content.lower().startswith('<!doctype'):
doctype_end = content.find('>') + 1
return content[:doctype_end] + '\n' + path_comment + content[doctype_end:]
return path_comment + content
def clean_claude_directory(self):
if self.claude_dir.exists():
shutil.rmtree(self.claude_dir)
self.claude_dir.mkdir()
print(f"Directorio claude limpiado: {self.claude_dir}")
def copy_files(self):
self.clean_claude_directory()
for root, dirs, files in os.walk(self.source_dir):
dirs[:] = [d for d in dirs if not self.should_skip_directory(d)]
current_path = Path(root)
for file in files:
file_path = current_path / file
if file.endswith(('.py', '.js', '.css', '.html', '.json', '.yml', '.yaml',
'.tsx', '.ts', '.jsx', '.scss', '.less')):
target_path = self.claude_dir / file
# Si el archivo ya existe en el directorio claude, agregar un sufijo numérico
if target_path.exists():
base = target_path.stem
ext = target_path.suffix
counter = 1
while target_path.exists():
target_path = self.claude_dir / f"{base}_{counter}{ext}"
counter += 1
try:
# Leer el contenido del archivo
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Agregar el comentario con la ruta si no existe
modified_content = self.add_path_comment(file_path, content)
# Escribir el nuevo contenido
with open(target_path, 'w', encoding='utf-8', newline='\n') as f:
f.write(modified_content)
self.file_mapping[str(file_path)] = target_path.name
print(f"Copiado: {file_path} -> {target_path}")
except UnicodeDecodeError:
print(f"Advertencia: No se pudo procesar {file_path} como texto. Copiando sin modificar...")
shutil.copy2(file_path, target_path)
except Exception as e:
print(f"Error procesando {file_path}: {str(e)}")
def generate_tree_report(self):
"""Genera el reporte en formato árbol visual"""
report = ["Estructura del proyecto original:\n"]
def add_to_report(path, prefix="", is_last=True):
report.append(prefix + ("└── " if is_last else "├── ") + path.name)
if path.is_dir() and not self.should_skip_directory(path.name):
children = sorted(path.iterdir(), key=lambda x: (x.is_file(), x.name))
children = [c for c in children if not (c.is_dir() and self.should_skip_directory(c.name))]
for i, child in enumerate(children):
is_last_child = i == len(children) - 1
new_prefix = prefix + (" " if is_last else "")
add_to_report(child, new_prefix, is_last_child)
add_to_report(self.source_dir)
report_path = self.claude_dir / "project_structure.txt"
with open(report_path, "w", encoding="utf-8") as f:
f.write("\n".join(report))
print(f"\nReporte generado en: {report_path}")
def main():
try:
print("Iniciando organización de archivos para Claude...")
organizer = ClaudeProjectOrganizer()
organizer.copy_files()
organizer.generate_tree_report()
print("\n¡Proceso completado exitosamente!")
except Exception as e:
print(f"\nError durante la ejecución: {str(e)}")
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
{
"type": "object",
"properties": {
"api_key": {
"type": "string",
"title": "API Key",
"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"
]
}
}
}

View File

@ -1,4 +1,20 @@
{ {
"type": "object", "type": "object",
"properties": {} "properties": {
"api_key": {
"type": "string",
"title": "API Key",
"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"
]
}
}
} }

View File

@ -1,22 +1,22 @@
[17:26:22] Iniciando ejecución de x1.py en C:\Estudio... [20:54:12] Iniciando ejecución de x1.py en C:\Estudio...
[17:26:22] === Ejecutando Script de Prueba 1 === [20:54:12] === Ejecutando Script de Prueba 1 ===
[17:26:22] Configuraciones cargadas: [20:54:12] Configuraciones cargadas:
[17:26:22] Nivel 1: { [20:54:12] Nivel 1: {
[17:26:22] "api_key": "your-api-key-here", [20:54:12] "api_key": "your-api-key-here",
[17:26:22] "model": "gpt-3.5-turbo" [20:54:12] "model": "gpt-3.5-turbo"
[17:26:22] } [20:54:12] }
[17:26:22] Nivel 2: { [20:54:12] Nivel 2: {
[17:26:22] "input_dir": "D:/Datos/Entrada", [20:54:12] "input_dir": "D:/Datos/Entrada",
[17:26:22] "output_dir": "D:/Datos/Salida", [20:54:12] "output_dir": "D:/Datos/Salida",
[17:26:22] "batch_size": 50 [20:54:12] "batch_size": 50
[17:26:22] } [20:54:12] }
[17:26:22] Nivel 3: {} [20:54:12] Nivel 3: {}
[17:26:22] Simulando procesamiento... [20:54:12] Simulando procesamiento...
[17:26:23] Progreso: 20% [20:54:13] Progreso: 20%
[17:26:24] Progreso: 40% [20:54:14] Progreso: 40%
[17:26:25] Progreso: 60% [20:54:15] Progreso: 60%
[17:26:26] Progreso: 80% [20:54:16] Progreso: 80%
[17:26:27] Progreso: 100% [20:54:17] Progreso: 100%
[17:26:27] ¡Proceso completado! [20:54:17] ¡Proceso completado!
[17:26:27] Ejecución de x1.py finalizada (success). Duración: 0:00:05.167151. [20:54:17] Ejecución de x1.py finalizada (success). Duración: 0:00:05.196719.
[17:26:27] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\example_group\log_x1.txt [20:54:17] Log completo guardado en: d:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\example_group\log_x1.txt