MargeCode / app.py
ancerlop's picture
Interfaz Gradio
4c22a32 verified
raw
history blame
6.3 kB
from flask import Flask, request, jsonify
import subprocess
import os
import tempfile
import uuid
import time
import logging
from flask_cors import CORS
import gradio as gr
import requests
app = Flask(__name__)
CORS(app) # Habilitar CORS para todas las rutas
# Configuraci贸n de logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Directorio temporal para los archivos de c贸digo
TEMP_DIR = os.path.join(tempfile.gettempdir(), '42coderunner')
os.makedirs(TEMP_DIR, exist_ok=True)
# Tiempo m谩ximo de ejecuci贸n (en segundos)
MAX_EXECUTION_TIME = 10 # Aumentamos un poco para Gradio
# URL base de la API (para la interfaz Gradio)
# Detecta si estamos en Hugging Face Spaces
API_BASE_URL = os.environ.get("SPACE_HOST")
if API_BASE_URL:
# En Hugging Face, usa la URL p煤blica del espacio
# Aseg煤rate de que el protocolo sea https
API_BASE_URL = f"https://{API_BASE_URL}"
else:
# Localmente, usa localhost
API_BASE_URL = "http://localhost:5000"
API_EXECUTE_URL = f"{API_BASE_URL}/api/execute"
# --- Funciones de la API Flask ---
@app.route('/api/execute', methods=['POST'])
def execute_code():
try:
# Obtener el c贸digo C del request
data = request.get_json()
if not data or 'code' not in data:
return jsonify({'success': False, 'error': 'No se proporcion贸 c贸digo'}), 400
code = data['code']
# Crear un ID 煤nico para este trabajo
job_id = str(uuid.uuid4())
# Crear archivos temporales para el c贸digo y la salida
code_file = os.path.join(TEMP_DIR, f"{job_id}.c")
executable = os.path.join(TEMP_DIR, f"{job_id}.exe")
# Guardar el c贸digo en un archivo temporal
with open(code_file, 'w') as f:
f.write(code)
# Compilar el c贸digo
logger.info(f"Compilando c贸digo para job {job_id}")
compile_process = subprocess.run(
['gcc', code_file, '-o', executable],
capture_output=True,
text=True
)
# Verificar si la compilaci贸n fue exitosa
if compile_process.returncode != 0:
return jsonify({
'success': False,
'error': compile_process.stderr
})
# Ejecutar el c贸digo compilado
logger.info(f"Ejecutando c贸digo para job {job_id}")
try:
start_time = time.time()
run_process = subprocess.run(
[executable],
capture_output=True,
text=True,
timeout=MAX_EXECUTION_TIME
)
execution_time = time.time() - start_time
# Preparar la respuesta
result = {
'success': run_process.returncode == 0,
'output': run_process.stdout,
'error': run_process.stderr,
'execution_time': execution_time
}
except subprocess.TimeoutExpired:
result = {
'success': False,
'error': f'La ejecuci贸n excedi贸 el tiempo l铆mite de {MAX_EXECUTION_TIME} segundos'
}
# Limpiar archivos temporales
try:
os.remove(code_file)
if os.path.exists(executable):
os.remove(executable)
except Exception as e:
logger.error(f"Error al limpiar archivos temporales: {e}")
return jsonify(result)
except Exception as e:
logger.error(f"Error inesperado: {e}")
return jsonify({'success': False, 'error': f'Error interno del servidor: {str(e)}'}), 500
@app.route('/api/health', methods=['GET'])
def health_check():
"""Basic health check endpoint."""
logger.info("Health check requested.")
# A simple health check is enough for Hugging Face
# The previous checks (compiler, temp dir) might fail in the HF environment
return jsonify({'status': 'ok', 'timestamp': time.time()})
# --- Interfaz Gradio ---
def run_c_code(c_code):
"""Funci贸n que se ejecuta cuando el usuario env铆a c贸digo C a trav茅s de Gradio."""
logger.info(f"Solicitud Gradio recibida. URL API: {API_EXECUTE_URL}")
try:
response = requests.post(API_EXECUTE_URL, json={'code': c_code}, timeout=MAX_EXECUTION_TIME + 5) # Timeout un poco mayor para la request
response.raise_for_status() # Lanza excepci贸n para errores HTTP
data = response.json()
if data.get('success'):
output = f"--- Salida ({data.get('execution_time', 0):.4f}s) ---\n{data.get('output', '')}"
if data.get('error'): # Mostrar stderr aunque la ejecuci贸n sea exitosa (warnings, etc.)
output += f"\n\n--- Errores (stderr) ---\n{data['error']}"
return output
else:
return f"--- Error ---\n{data.get('error', 'Error desconocido')}"
except requests.exceptions.RequestException as e:
logger.error(f"Error de red al llamar a la API: {e}")
return f"Error de red al conectar con el backend: {e}"
except Exception as e:
logger.error(f"Error inesperado en la interfaz Gradio: {e}")
return f"Error inesperado en la interfaz: {str(e)}"
# Ejemplo de c贸digo C para la interfaz
EXAMPLE_CODE = """#include <stdio.h>
int main() {
printf("隆Hola desde 42CodeRunner!\n");
return 0;
}
"""
# Crear la interfaz Gradio
iface = gr.Interface(
fn=run_c_code,
inputs=gr.Code(language="c", label="C贸digo C", value=EXAMPLE_CODE),
outputs=gr.Textbox(label="Resultado de la Ejecuci贸n", lines=15),
title="馃強u200d鈾傦笍 42CodeRunner",
description="Escribe tu c贸digo C, haz clic en 'Submit' y mira la magia suceder. Ejecutado de forma segura en el backend.",
allow_flagging='never'
)
# Montar la interfaz Gradio en la app Flask en la ruta ra铆z
app = gr.mount_gradio_app(app, iface, path="/")
# --- Ejecuci贸n de la App ---
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)