Turn evaluator/network failures into readable errors instead of a bare 500
Browse files
app.py
CHANGED
|
@@ -25,6 +25,7 @@ from __future__ import annotations
|
|
| 25 |
|
| 26 |
import json
|
| 27 |
import os
|
|
|
|
| 28 |
|
| 29 |
import gradio as gr
|
| 30 |
import pandas as pd
|
|
@@ -32,6 +33,13 @@ import requests
|
|
| 32 |
from gradio_client import Client, handle_file
|
| 33 |
from huggingface_hub import hf_hub_download
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
HF_TOKEN = os.environ["HF_TOKEN"]
|
| 36 |
BACKEND = os.environ.get("BACKEND_SPACE", "nvidia/PhysicalAI-OOD-Evaluator-Private")
|
| 37 |
RESULTS_REPO = os.environ.get("RESULTS_REPO", "nvidia/PhysicalAI-OOD-Results")
|
|
@@ -171,13 +179,33 @@ def submit(pred_file, model_name, organization, track, publish,
|
|
| 171 |
if pred_file is None:
|
| 172 |
raise gr.Error("Please upload a submission.json file.")
|
| 173 |
progress(0.15, desc="Connecting to evaluator…")
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
progress(1.0, desc="Done")
|
| 182 |
# Refresh both boards (a submission only changes one, but refreshing both is cheap).
|
| 183 |
return md, load_leaderboard("track1"), load_leaderboard("track2")
|
|
|
|
| 25 |
|
| 26 |
import json
|
| 27 |
import os
|
| 28 |
+
import traceback
|
| 29 |
|
| 30 |
import gradio as gr
|
| 31 |
import pandas as pd
|
|
|
|
| 33 |
from gradio_client import Client, handle_file
|
| 34 |
from huggingface_hub import hf_hub_download
|
| 35 |
|
| 36 |
+
try:
|
| 37 |
+
# gradio_client wraps a `gr.Error` raised by the backend as AppError. Guarded
|
| 38 |
+
# because a missing import here would kill the Space at startup.
|
| 39 |
+
from gradio_client.exceptions import AppError
|
| 40 |
+
except ImportError: # pragma: no cover - fall back to the class-name check below
|
| 41 |
+
AppError = None
|
| 42 |
+
|
| 43 |
HF_TOKEN = os.environ["HF_TOKEN"]
|
| 44 |
BACKEND = os.environ.get("BACKEND_SPACE", "nvidia/PhysicalAI-OOD-Evaluator-Private")
|
| 45 |
RESULTS_REPO = os.environ.get("RESULTS_REPO", "nvidia/PhysicalAI-OOD-Results")
|
|
|
|
| 179 |
if pred_file is None:
|
| 180 |
raise gr.Error("Please upload a submission.json file.")
|
| 181 |
progress(0.15, desc="Connecting to evaluator…")
|
| 182 |
+
try:
|
| 183 |
+
client = Client(BACKEND, token=HF_TOKEN)
|
| 184 |
+
progress(0.4, desc="Running GPU evaluation (this can take a minute)…")
|
| 185 |
+
row, md = client.predict(
|
| 186 |
+
handle_file(pred_file), model_name.strip(), organization.strip(), email,
|
| 187 |
+
bool(publish), track, profile.username, str(profile.get("sub") or ""),
|
| 188 |
+
api_name="/evaluate",
|
| 189 |
+
)
|
| 190 |
+
except gr.Error:
|
| 191 |
+
raise
|
| 192 |
+
except Exception as e:
|
| 193 |
+
# Anything that is not a gr.Error arrives here as a bare exception, which
|
| 194 |
+
# Gradio renders as an unparseable 500 ("Unexpected token 'I'") rather than
|
| 195 |
+
# a message -- so turn every path into something the participant can act on.
|
| 196 |
+
traceback.print_exc()
|
| 197 |
+
from_backend = (AppError is not None and isinstance(e, AppError)) or \
|
| 198 |
+
type(e).__name__ == "AppError"
|
| 199 |
+
if from_backend:
|
| 200 |
+
# The evaluator rejected the submission on purpose; its message is
|
| 201 |
+
# already written for the participant.
|
| 202 |
+
raise gr.Error(str(e)) from e
|
| 203 |
+
raise gr.Error(
|
| 204 |
+
"Could not reach the evaluator, so nothing was scored. This is on our "
|
| 205 |
+
"side, not your file — please retry in a few minutes. If it keeps "
|
| 206 |
+
"failing, report it with your HF username and the time, quoting: "
|
| 207 |
+
f"{type(e).__name__}: {e}"
|
| 208 |
+
) from e
|
| 209 |
progress(1.0, desc="Done")
|
| 210 |
# Refresh both boards (a submission only changes one, but refreshing both is cheap).
|
| 211 |
return md, load_leaderboard("track1"), load_leaderboard("track2")
|