File size: 7,878 Bytes
dfdeeec
1a0754f
 
2d87186
 
 
 
 
 
 
4f65d0c
 
0514da3
1a0754f
4f65d0c
 
 
 
 
6f25aa9
4f65d0c
 
 
cae5048
 
 
4f65d0c
 
0514da3
 
 
 
 
 
 
 
 
 
 
 
 
4f65d0c
 
 
 
 
cae5048
4f65d0c
cae5048
4f65d0c
 
 
 
 
cae5048
 
07e02e0
4f65d0c
07e02e0
0514da3
cae5048
0834c9b
 
 
 
 
4f65d0c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a0754f
4f65d0c
 
 
1a0754f
2d87186
4f65d0c
 
2d87186
1a0754f
2d87186
1a0754f
2d87186
1a0754f
 
2d87186
 
4f65d0c
2d87186
4f65d0c
 
 
2d87186
 
4f65d0c
 
 
 
 
2d87186
 
 
4f65d0c
2d87186
 
4f65d0c
2d87186
 
 
 
 
4f65d0c
2d87186
 
1a0754f
2d87186
 
 
4f65d0c
2d87186
4f65d0c
 
 
2d87186
1a0754f
 
 
4f65d0c
 
 
 
1a0754f
 
 
 
 
 
4f65d0c
 
 
 
 
 
 
 
 
 
1a0754f
4f65d0c
1a0754f
 
2d87186
 
 
1a0754f
 
 
 
 
 
2d87186
 
 
4f65d0c
2d87186
 
 
 
 
1a0754f
 
 
4f65d0c
 
 
1a0754f
2d87186
4f65d0c
1a0754f
4f65d0c
1a0754f
 
 
 
 
 
2d87186
 
 
 
 
1a0754f
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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", "[email protected]")

    # Forzar la URL remota para que lleve el token
    # user: "__token__" (literal) y password: <token>
    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()