config_manager dividido en partes para que no sea tan grande
This commit is contained in:
parent
d63abc971c
commit
c759a756be
Binary file not shown.
57
app.py
57
app.py
|
@ -1,6 +1,6 @@
|
|||
from flask import Flask, render_template, request, jsonify, url_for
|
||||
from flask_sock import Sock
|
||||
from config_manager import ConfigurationManager
|
||||
from lib.config_manager import ConfigurationManager
|
||||
import os
|
||||
import json # Added import
|
||||
from datetime import datetime
|
||||
|
@ -46,7 +46,7 @@ def broadcast_message(message):
|
|||
dead_connections = set()
|
||||
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):
|
||||
messages = message
|
||||
else:
|
||||
|
@ -54,32 +54,32 @@ def broadcast_message(message):
|
|||
messages = [line.strip() for line in message.splitlines() if line.strip()]
|
||||
|
||||
# Procesar cada mensaje
|
||||
for msg in messages:
|
||||
for raw_msg in messages:
|
||||
# Limpiar timestamps duplicados al inicio del mensaje
|
||||
while msg.startswith("[") and "]" in msg:
|
||||
while raw_msg.startswith("[") and "]" in raw_msg:
|
||||
try:
|
||||
closing_bracket = msg.index("]") + 1
|
||||
if msg[1 : closing_bracket - 1].replace(":", "").isdigit():
|
||||
msg = msg[closing_bracket:].strip()
|
||||
closing_bracket = raw_msg.index("]") + 1
|
||||
if raw_msg[1 : closing_bracket - 1].replace(":", "").isdigit():
|
||||
raw_msg = raw_msg[closing_bracket:].strip() # Update raw_msg itself
|
||||
else:
|
||||
break
|
||||
except:
|
||||
break
|
||||
|
||||
# Añadir un único timestamp
|
||||
formatted_msg = f"{timestamp}{msg}"
|
||||
# Log the raw message using the config_manager's logger
|
||||
# The logger will handle its own timestamping for the file.
|
||||
config_manager.append_log(raw_msg)
|
||||
|
||||
# Escribir en el archivo de log
|
||||
with open(config_manager.log_file, "a", encoding="utf-8") as f:
|
||||
f.write(f"{formatted_msg}\n")
|
||||
# Format message with timestamp *for WebSocket broadcast*
|
||||
formatted_msg_for_ws = f"{timestamp}{raw_msg}"
|
||||
|
||||
# Enviar a todos los clientes WebSocket
|
||||
for ws in list(websocket_connections):
|
||||
try:
|
||||
if ws.connected:
|
||||
ws.send(f"{formatted_msg}\n")
|
||||
if ws.connected: # Check if ws is still connected before sending
|
||||
ws.send(f"{formatted_msg_for_ws}\n") # Use the correct variable name here
|
||||
except Exception:
|
||||
dead_connections.add(ws)
|
||||
dead_connections.add(ws) # Collect dead connections
|
||||
|
||||
# Limpiar conexiones muertas
|
||||
websocket_connections.difference_update(dead_connections)
|
||||
|
@ -205,30 +205,19 @@ def handle_logs():
|
|||
|
||||
@app.route("/api/group-description/<group>", methods=["GET", "POST"])
|
||||
def handle_group_description(group):
|
||||
description_path = os.path.join(
|
||||
config_manager.script_groups_path, group, "description.json"
|
||||
)
|
||||
|
||||
if request.method == "GET":
|
||||
try:
|
||||
with open(description_path, "r", encoding="utf-8") as f:
|
||||
return jsonify(json.load(f))
|
||||
except FileNotFoundError:
|
||||
return jsonify(
|
||||
{
|
||||
"name": group,
|
||||
"description": "Sin descripción",
|
||||
"version": "1.0",
|
||||
"author": "Unknown",
|
||||
}
|
||||
)
|
||||
details = config_manager.get_group_details(group)
|
||||
if "error" in details:
|
||||
return jsonify(details), 404 # Group not found
|
||||
return jsonify(details)
|
||||
except Exception as e:
|
||||
return jsonify({"status": "error", "message": str(e)}), 500
|
||||
else: # POST
|
||||
try:
|
||||
data = request.json
|
||||
os.makedirs(os.path.dirname(description_path), exist_ok=True)
|
||||
with open(description_path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
return jsonify({"status": "success"})
|
||||
result = config_manager.update_group_description(group, data)
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
return jsonify({"status": "error", "message": str(e)}), 500
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -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 ---
|
|
@ -1,9 +1,9 @@
|
|||
--- Log de Ejecución: x1.py ---
|
||||
Grupo: example_group
|
||||
Directorio de Trabajo: C:\Estudio
|
||||
Inicio: 2025-05-03 17:26:22
|
||||
Fin: 2025-05-03 17:26:27
|
||||
Duración: 0:00:05.167151
|
||||
Inicio: 2025-05-03 20:54:12
|
||||
Fin: 2025-05-03 20:54:17
|
||||
Duración: 0:00:05.196719
|
||||
Estado: SUCCESS (Código de Salida: 0)
|
||||
|
||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
--- Log de Ejecución: x2.py ---
|
||||
Grupo: example_group
|
||||
Directorio de Trabajo: C:\Estudio
|
||||
Inicio: 2025-05-03 17:26:13
|
||||
Fin: 2025-05-03 17:26:14
|
||||
Duración: 0:00:01.149705
|
||||
Inicio: 2025-05-03 20:48:23
|
||||
Fin: 2025-05-03 20:48:27
|
||||
Duración: 0:00:03.208350
|
||||
Estado: SUCCESS (Código de Salida: 0)
|
||||
|
||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||
|
@ -11,6 +11,10 @@ Estado: SUCCESS (Código de Salida: 0)
|
|||
|
||||
Iniciando análisis de datos simulado...
|
||||
Analizando lote 1...
|
||||
Lote 1 completado exitosamente
|
||||
Analizando lote 2...
|
||||
Lote 2 completado exitosamente
|
||||
Analizando lote 3...
|
||||
|
||||
ERROR: Error simulado en el procesamiento
|
||||
El proceso se detuvo debido a un error
|
||||
|
|
|
@ -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()
|
1010
config_manager.py
1010
config_manager.py
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,20 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
44
data/log.txt
44
data/log.txt
|
@ -1,22 +1,22 @@
|
|||
[17:26:22] Iniciando ejecución de x1.py en C:\Estudio...
|
||||
[17:26:22] === Ejecutando Script de Prueba 1 ===
|
||||
[17:26:22] Configuraciones cargadas:
|
||||
[17:26:22] Nivel 1: {
|
||||
[17:26:22] "api_key": "your-api-key-here",
|
||||
[17:26:22] "model": "gpt-3.5-turbo"
|
||||
[17:26:22] }
|
||||
[17:26:22] Nivel 2: {
|
||||
[17:26:22] "input_dir": "D:/Datos/Entrada",
|
||||
[17:26:22] "output_dir": "D:/Datos/Salida",
|
||||
[17:26:22] "batch_size": 50
|
||||
[17:26:22] }
|
||||
[17:26:22] Nivel 3: {}
|
||||
[17:26:22] Simulando procesamiento...
|
||||
[17:26:23] Progreso: 20%
|
||||
[17:26:24] Progreso: 40%
|
||||
[17:26:25] Progreso: 60%
|
||||
[17:26:26] Progreso: 80%
|
||||
[17:26:27] Progreso: 100%
|
||||
[17:26:27] ¡Proceso completado!
|
||||
[17:26:27] Ejecución de x1.py finalizada (success). Duración: 0:00:05.167151.
|
||||
[17:26:27] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\example_group\log_x1.txt
|
||||
[20:54:12] Iniciando ejecución de x1.py en C:\Estudio...
|
||||
[20:54:12] === Ejecutando Script de Prueba 1 ===
|
||||
[20:54:12] Configuraciones cargadas:
|
||||
[20:54:12] Nivel 1: {
|
||||
[20:54:12] "api_key": "your-api-key-here",
|
||||
[20:54:12] "model": "gpt-3.5-turbo"
|
||||
[20:54:12] }
|
||||
[20:54:12] Nivel 2: {
|
||||
[20:54:12] "input_dir": "D:/Datos/Entrada",
|
||||
[20:54:12] "output_dir": "D:/Datos/Salida",
|
||||
[20:54:12] "batch_size": 50
|
||||
[20:54:12] }
|
||||
[20:54:12] Nivel 3: {}
|
||||
[20:54:12] Simulando procesamiento...
|
||||
[20:54:13] Progreso: 20%
|
||||
[20:54:14] Progreso: 40%
|
||||
[20:54:15] Progreso: 60%
|
||||
[20:54:16] Progreso: 80%
|
||||
[20:54:17] Progreso: 100%
|
||||
[20:54:17] ¡Proceso completado!
|
||||
[20:54:17] Ejecución de x1.py finalizada (success). Duración: 0:00:05.196719.
|
||||
[20:54:17] Log completo guardado en: d:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\example_group\log_x1.txt
|
||||
|
|
Loading…
Reference in New Issue