Spaces:
Sleeping
Sleeping
Clémentine
commited on
Commit
·
32de2c3
1
Parent(s):
9fec70b
nicer display, restart on select column
Browse files- app.py +26 -34
- requirements.txt +1 -1
- utils/io.py +57 -53
- utils/jobs.py +8 -11
app.py
CHANGED
|
@@ -44,30 +44,17 @@ def create_app() -> gr.Blocks:
|
|
| 44 |
gr.Markdown("## Job Results")
|
| 45 |
results_table = gr.Dataframe(
|
| 46 |
value=get_results_table(),
|
| 47 |
-
interactive=
|
|
|
|
|
|
|
|
|
|
| 48 |
wrap=True,
|
| 49 |
-
|
|
|
|
|
|
|
| 50 |
)
|
| 51 |
refresh_btn = gr.Button("Refresh Results")
|
| 52 |
|
| 53 |
-
with gr.Row():
|
| 54 |
-
with gr.Column():
|
| 55 |
-
gr.Markdown("## Relaunch Individual Job")
|
| 56 |
-
|
| 57 |
-
# Load model-provider combinations
|
| 58 |
-
|
| 59 |
-
relaunch_model = gr.Dropdown(
|
| 60 |
-
label="Model",
|
| 61 |
-
choices=[],
|
| 62 |
-
interactive=True
|
| 63 |
-
)
|
| 64 |
-
relaunch_provider = gr.Dropdown(
|
| 65 |
-
label="Provider",
|
| 66 |
-
choices=[],
|
| 67 |
-
interactive=True
|
| 68 |
-
)
|
| 69 |
-
relaunch_btn = gr.Button("Relaunch Job", variant="secondary")
|
| 70 |
-
|
| 71 |
def update_model_choices() -> gr.update:
|
| 72 |
models_providers = load_models_providers(globals.LOCAL_CONFIG_FILE)
|
| 73 |
model_choices = sorted(list(set([mp[0] for mp in models_providers])))
|
|
@@ -91,11 +78,6 @@ def create_app() -> gr.Blocks:
|
|
| 91 |
outputs=output
|
| 92 |
)
|
| 93 |
|
| 94 |
-
init_btn.click(
|
| 95 |
-
fn=update_model_choices,
|
| 96 |
-
outputs=relaunch_model
|
| 97 |
-
)
|
| 98 |
-
|
| 99 |
launch_btn.click(
|
| 100 |
fn=launch_jobs,
|
| 101 |
outputs=output
|
|
@@ -106,16 +88,26 @@ def create_app() -> gr.Blocks:
|
|
| 106 |
outputs=results_table
|
| 107 |
)
|
| 108 |
|
| 109 |
-
#
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
-
|
| 117 |
-
fn=
|
| 118 |
-
inputs=[
|
| 119 |
outputs=output
|
| 120 |
)
|
| 121 |
|
|
|
|
| 44 |
gr.Markdown("## Job Results")
|
| 45 |
results_table = gr.Dataframe(
|
| 46 |
value=get_results_table(),
|
| 47 |
+
interactive=True,
|
| 48 |
+
show_search="search",
|
| 49 |
+
show_copy_button=True,
|
| 50 |
+
show_fullscreen_button=True,
|
| 51 |
wrap=True,
|
| 52 |
+
static_columns=list(range(7)),
|
| 53 |
+
datatype=["str", "str", "str", "str", "str", "str", "html", "str"],
|
| 54 |
+
elem_id="results_table"
|
| 55 |
)
|
| 56 |
refresh_btn = gr.Button("Refresh Results")
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
def update_model_choices() -> gr.update:
|
| 59 |
models_providers = load_models_providers(globals.LOCAL_CONFIG_FILE)
|
| 60 |
model_choices = sorted(list(set([mp[0] for mp in models_providers])))
|
|
|
|
| 78 |
outputs=output
|
| 79 |
)
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
launch_btn.click(
|
| 82 |
fn=launch_jobs,
|
| 83 |
outputs=output
|
|
|
|
| 88 |
outputs=results_table
|
| 89 |
)
|
| 90 |
|
| 91 |
+
# Handle dataframe cell selection for relaunch
|
| 92 |
+
def handle_table_select(evt: gr.SelectData):
|
| 93 |
+
"""Handle when a cell in the results table is clicked."""
|
| 94 |
+
print(f"[Relaunch] Cell selected - Row: {evt.index[0]}, Col: {evt.index[1]}, Value: {evt.value}")
|
| 95 |
+
|
| 96 |
+
# Check if the Actions column (index 7) was clicked
|
| 97 |
+
if evt.index[1] == 7:
|
| 98 |
+
# Get the full row data from the dataframe
|
| 99 |
+
df = get_results_table()
|
| 100 |
+
row_data = df.data.iloc[evt.index[0]]
|
| 101 |
+
|
| 102 |
+
model = row_data['Model']
|
| 103 |
+
provider = row_data['Provider']
|
| 104 |
+
print(f"[Relaunch] Relaunching job - Model: {model}, Provider: {provider}")
|
| 105 |
+
|
| 106 |
+
return run_single_job(model, provider, globals.TASKS)
|
| 107 |
|
| 108 |
+
results_table.select(
|
| 109 |
+
fn=handle_table_select,
|
| 110 |
+
inputs=[],
|
| 111 |
outputs=output
|
| 112 |
)
|
| 113 |
|
requirements.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
gradio>=
|
| 2 |
huggingface-hub>=0.20.0
|
| 3 |
apscheduler>=3.10.0
|
| 4 |
datasets>=2.14.0
|
|
|
|
| 1 |
+
gradio>=5.49.0
|
| 2 |
huggingface-hub>=0.20.0
|
| 3 |
apscheduler>=3.10.0
|
| 4 |
datasets>=2.14.0
|
utils/io.py
CHANGED
|
@@ -70,22 +70,21 @@ def load_models_providers(file_path: str = globals.LOCAL_CONFIG_FILE) -> List[Tu
|
|
| 70 |
def save_results() -> None:
|
| 71 |
"""Persist job results to HuggingFace dataset."""
|
| 72 |
try:
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
print(f"Saved {len(records)} results to dataset")
|
| 89 |
|
| 90 |
except Exception as e:
|
| 91 |
print(f"Error saving results to dataset: {e}")
|
|
@@ -132,41 +131,46 @@ def style_status(val):
|
|
| 132 |
|
| 133 |
def get_results_table():
|
| 134 |
"""Return job results as a styled pandas DataFrame for Gradio DataFrame."""
|
| 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 |
|
|
|
|
| 70 |
def save_results() -> None:
|
| 71 |
"""Persist job results to HuggingFace dataset."""
|
| 72 |
try:
|
| 73 |
+
if not globals.job_results:
|
| 74 |
+
print("No results to save")
|
| 75 |
+
return
|
| 76 |
+
|
| 77 |
+
records = list(globals.job_results.values())
|
| 78 |
+
df = pd.DataFrame(records)
|
| 79 |
+
dataset = Dataset.from_pandas(df)
|
| 80 |
+
|
| 81 |
+
# Push to HuggingFace Hub
|
| 82 |
+
dataset.push_to_hub(
|
| 83 |
+
globals.RESULTS_DATASET_NAME,
|
| 84 |
+
token=os.getenv("HF_TOKEN"),
|
| 85 |
+
private=False
|
| 86 |
+
)
|
| 87 |
+
print(f"Saved {len(records)} results to dataset")
|
|
|
|
| 88 |
|
| 89 |
except Exception as e:
|
| 90 |
print(f"Error saving results to dataset: {e}")
|
|
|
|
| 131 |
|
| 132 |
def get_results_table():
|
| 133 |
"""Return job results as a styled pandas DataFrame for Gradio DataFrame."""
|
| 134 |
+
if not globals.job_results:
|
| 135 |
+
return pd.DataFrame(columns=["Model", "Provider", "Last Run", "Status", "Current Score", "Previous Score", "Latest Job Id"])
|
| 136 |
+
|
| 137 |
+
table_data = []
|
| 138 |
+
for key, info in globals.job_results.items():
|
| 139 |
+
current_score = info.get("current_score", "N/A")
|
| 140 |
+
if current_score is not None and isinstance(current_score, (int, float)):
|
| 141 |
+
current_score = f"{current_score:.4f}"
|
| 142 |
+
|
| 143 |
+
previous_score = info.get("previous_score", "N/A")
|
| 144 |
+
if previous_score is not None and isinstance(previous_score, (int, float)):
|
| 145 |
+
previous_score = f"{previous_score:.4f}"
|
| 146 |
+
|
| 147 |
+
job_id = info.get("job_id", "N/A")
|
| 148 |
+
# Create a clickable link for the job ID
|
| 149 |
+
if job_id != "N/A":
|
| 150 |
+
job_url = f"https://hf.co/jobs/{globals.NAMESPACE}/{job_id}"
|
| 151 |
+
job_link = f'{job_id}: <a href="{job_url}" target="_blank">📄</a> '
|
| 152 |
+
else:
|
| 153 |
+
job_link = job_id
|
| 154 |
+
|
| 155 |
+
# Create relaunch link with data attributes for JavaScript to access
|
| 156 |
+
model = info["model"]
|
| 157 |
+
provider = info["provider"]
|
| 158 |
+
relaunch_link = '🔄 Relaunch'
|
| 159 |
+
|
| 160 |
+
table_data.append([
|
| 161 |
+
model,
|
| 162 |
+
provider,
|
| 163 |
+
info["last_run"],
|
| 164 |
+
info["status"],
|
| 165 |
+
current_score,
|
| 166 |
+
previous_score,
|
| 167 |
+
job_link,
|
| 168 |
+
relaunch_link
|
| 169 |
+
])
|
| 170 |
+
|
| 171 |
+
df = pd.DataFrame(table_data, columns=["Model", "Provider", "Last Run", "Status", "Current Score", "Previous Score", "Job Id and Logs", "Actions"])
|
| 172 |
+
|
| 173 |
+
# Apply styling to the Status column
|
| 174 |
+
styled_df = df.style.map(style_status, subset=['Status'])
|
| 175 |
+
return styled_df
|
| 176 |
|
utils/jobs.py
CHANGED
|
@@ -57,7 +57,7 @@ def extract_score_from_job(job_id: str) -> Optional[float]:
|
|
| 57 |
return None
|
| 58 |
|
| 59 |
|
| 60 |
-
def run_single_job(model: str, provider: str, tasks: str) -> Optional[str]:
|
| 61 |
"""Run a single job for a model-provider combination."""
|
| 62 |
|
| 63 |
if not model or not provider:
|
|
@@ -72,12 +72,11 @@ def run_single_job(model: str, provider: str, tasks: str) -> Optional[str]:
|
|
| 72 |
|
| 73 |
# Check if job is already running
|
| 74 |
key = globals.get_model_provider_key(model, provider)
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
return -1
|
| 81 |
|
| 82 |
print(f"Starting job for model={model}, provider={provider}")
|
| 83 |
|
|
@@ -145,13 +144,11 @@ def launch_jobs(tasks: str = globals.TASKS, config_file: str = globals.LOCAL_CON
|
|
| 145 |
def update_job_statuses() -> None:
|
| 146 |
"""Check and update the status of active jobs."""
|
| 147 |
try:
|
| 148 |
-
|
| 149 |
-
keys = list(globals.job_results.keys())
|
| 150 |
|
| 151 |
for key in keys:
|
| 152 |
try:
|
| 153 |
-
|
| 154 |
-
job_id = globals.job_results[key]["job_id"]
|
| 155 |
|
| 156 |
job_info = inspect_job(job_id=job_id, namespace=globals.NAMESPACE)
|
| 157 |
new_status = job_info.status.stage
|
|
|
|
| 57 |
return None
|
| 58 |
|
| 59 |
|
| 60 |
+
def run_single_job(model: str, provider: str, tasks: str = globals.TASKS) -> Optional[str]:
|
| 61 |
"""Run a single job for a model-provider combination."""
|
| 62 |
|
| 63 |
if not model or not provider:
|
|
|
|
| 72 |
|
| 73 |
# Check if job is already running
|
| 74 |
key = globals.get_model_provider_key(model, provider)
|
| 75 |
+
if key in globals.job_results:
|
| 76 |
+
current_status = globals.job_results[key].get("status")
|
| 77 |
+
if current_status == "RUNNING":
|
| 78 |
+
print( f"Job for {model} on {provider} is already running. Please wait for it to complete.")
|
| 79 |
+
return -1
|
|
|
|
| 80 |
|
| 81 |
print(f"Starting job for model={model}, provider={provider}")
|
| 82 |
|
|
|
|
| 144 |
def update_job_statuses() -> None:
|
| 145 |
"""Check and update the status of active jobs."""
|
| 146 |
try:
|
| 147 |
+
keys = list(globals.job_results.keys())
|
|
|
|
| 148 |
|
| 149 |
for key in keys:
|
| 150 |
try:
|
| 151 |
+
job_id = globals.job_results[key]["job_id"]
|
|
|
|
| 152 |
|
| 153 |
job_info = inspect_job(job_id=job_id, namespace=globals.NAMESPACE)
|
| 154 |
new_status = job_info.status.stage
|