import gradio as gr import requests import os import pandas as pd import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import io import base64 import json import time import subprocess from huggingface_hub import Repository # ----------------------------------------------------------------------------- # CONFIGURACIÓN DEL REPO DEL SPACE Y DE LA REFERENCIA # ----------------------------------------------------------------------------- SPACE_REPO_URL = "https://huggingface.co/spaces/JulioContrerasH/my-challenge" SPACE_LOCAL_DIR = "." # Usa la carpeta actual (el mismo repo del Space) # URL de tu archivo de referencia CSV en un dataset (por ejemplo, "reference.csv") REFERENCE_FILE_URL = ( "https://huggingface.co/datasets/JulioContrerasH/my-challenge-submissions/resolve/main/reference.csv" ) LOCAL_REF_PATH = "reference.csv" # Lo guardaremos con este nombre local def git_set_identity(name: str, email: str): """Configura la identidad de git en el repo local.""" try: subprocess.run(["git", "config", "user.name", name], check=True) subprocess.run(["git", "config", "user.email", email], check=True) except Exception as e: print("Error setting git identity:", e) def setup_local_repo_for_push(): """ Inicializa un objeto 'Repository' apuntando al mismo repo del Space. Requiere un token con permisos de escritura, guardado en HF_SPACE_TOKEN como secret en la configuración del Space. También configura user_name y user_email para que los commits no den error. """ token = os.environ.get("HF_SPACE_TOKEN", None) # Revisar que se llame así en los secrets if not token: print("WARNING: HF_SPACE_TOKEN no está configurado. No se podrá hacer push.") return None repo = Repository( local_dir=SPACE_LOCAL_DIR, clone_from=SPACE_REPO_URL, use_auth_token=token ) # Configurar user.name y user.email git_set_identity("JulioContrerasH", "contrerasnetk@gmail.com") # Forzar la URL remota para que lleve el token # user: "__token__" (literal) y password: new_url = f"https://__token__:{token}@huggingface.co/spaces/JulioContrerasH/my-challenge" subprocess.run(["git", "remote", "set-url", "origin", new_url], cwd=".", check=True) # Por si se actualizó el Space en remoto try: repo.git_pull() except: pass return repo # Inicializamos la posibilidad de hacer push a nuestro Space space_repo = setup_local_repo_for_push() def add_submission_entry(entry): """ Abre/crea submissions.jsonl (en la raíz del Space), agrega la nueva 'entry', y hace commit+push al repo. """ global space_repo if space_repo is None: print("No repo handle (space_repo is None). Skipping save.") return submissions_file = "submissions.jsonl" # 1) Traer la última versión de remoto (por si hubo otros commits) space_repo.git_pull() # 2) Leer el archivo actual (si existe) submissions = [] if os.path.exists(submissions_file): with open(submissions_file, "r") as f: for line in f: line = line.strip() if line: submissions.append(json.loads(line)) # 3) Añadir la nueva entrada submissions.append(entry) # 4) Guardar sobrescribiendo with open(submissions_file, "w") as f: for s in submissions: f.write(json.dumps(s) + "\n") # 5) Hacer commit y push space_repo.git_add(submissions_file) space_repo.git_commit("Add new submission entry") try: space_repo.git_push() print("Submission pushed successfully to the Space repo.") except Exception as e: print("Error pushing submission:", e) # ----------------------------------------------------------------------------- # DESCARGA DEL ARCHIVO DE REFERENCIA # ----------------------------------------------------------------------------- def download_reference(): """ Descarga el CSV de referencia desde el dataset en Hugging Face, guardándolo como 'reference.csv' si no existe aún. """ if not os.path.exists(LOCAL_REF_PATH): print("Descargando archivo de referencia...") r = requests.get(REFERENCE_FILE_URL) r.raise_for_status() with open(LOCAL_REF_PATH, 'wb') as f: f.write(r.content) print("Descarga completa:", LOCAL_REF_PATH) download_reference() # Se ejecuta al iniciar el Space # ----------------------------------------------------------------------------- # LÓGICA DE EVALUACIÓN # ----------------------------------------------------------------------------- def evaluate_prediction(pred_path, ref_path): """ Lee el CSV subido (pred_path) y el CSV de referencia (ref_path), Calcula el MRE y RMSE, y retorna un dict con resultados. Formato esperado: - reference.csv: [wavelength, power] - predictions.csv: [wavelength, prediction] """ # Leer la referencia df_ref = pd.read_csv(ref_path) # Leer la predicción df_pred = pd.read_csv(pred_path) # Merge en base a 'wavelength' df_merged = pd.merge(df_ref, df_pred, on='wavelength', how='inner') real = df_merged['power'].values pred = df_merged['prediction'].values # Calcular MRE mre = np.abs((pred - real) / real) mre_mean = mre.mean() # Calcular RMSE rmse = np.sqrt(np.mean((pred - real)**2)) # Retornar return { "mre_mean": float(mre_mean), "rmse": float(rmse), "mre_spectrum": mre.tolist() } def evaluate_and_save(pred_file, participant_name): """ 1. Toma el archivo subido (pred_file). 2. Evalúa comparándolo con la referencia (LOCAL_REF_PATH). 3. Agrega la entrada a submissions.jsonl. 4. Genera una gráfica y mensaje de resultados. """ if not pred_file: return "No file uploaded", None pred_path = pred_file.name results = evaluate_prediction(pred_path, LOCAL_REF_PATH) # Guardar submission en submissions.jsonl submission_entry = { "submission_id": int(time.time()), "participant": participant_name, "mre_mean": results["mre_mean"], "rmse": results["rmse"], "timestamp": time.strftime("%Y-%m-%d %H:%M:%S") } add_submission_entry(submission_entry) # Graficar mre_spectrum = results["mre_spectrum"] plt.figure(figsize=(6,4)) plt.plot(np.arange(len(mre_spectrum)), mre_spectrum, marker='o', label='MRE Spectrum') plt.xlabel('Index') plt.ylabel('MRE') plt.title('Spectral Error') plt.legend() buf = io.BytesIO() plt.savefig(buf, format='png') plt.close() buf.seek(0) img_str = base64.b64encode(buf.read()).decode('utf-8') img_str = f"data:image/png;base64,{img_str}" # Mensaje final message = ( f"Participant: {participant_name}\n" f"MRE mean: {results['mre_mean']:.4f}\n" f"RMSE: {results['rmse']:.4f}" ) return message, img_str # ----------------------------------------------------------------------------- # INTERFAZ GRADIO # ----------------------------------------------------------------------------- with gr.Blocks() as demo: gr.Markdown("# My Challenge\nSube tu archivo de predicciones en CSV para evaluar tu modelo.") participant_name = gr.Textbox(label="Nombre del participante") pred_file = gr.File(label="Subir archivo CSV (predictions.csv)") output_message = gr.Textbox(label="Resultados") output_image = gr.HTML(label="Gráfica") submit_btn = gr.Button("Evaluar") submit_btn.click( fn=evaluate_and_save, inputs=[pred_file, participant_name], outputs=[output_message, output_image] ) demo.launch()