edmos7's picture
Show overlay slider instruction above media
4800aa1
Raw
History Blame Contribute Delete
7.3 kB
from __future__ import annotations
import json
from pathlib import Path
import gradio as gr
ROOT = Path(__file__).parent
MANIFEST_PATH = ROOT / "data" / "manifest.json"
CONDITION_LABELS = {
"dataset": "Dataset trajectory",
"draw": "Drawn trajectory",
"specialist": "No trajectory input",
}
def load_manifest() -> dict:
with MANIFEST_PATH.open(encoding="utf-8") as f:
return json.load(f)
MANIFEST = load_manifest()
RUNS = MANIFEST["runs"]
def score_label(score: float | None) -> str:
if score is None:
return "n/a"
return f"{score * 100:.1f}%"
def task_options() -> list[str]:
return ["All"] + sorted({run["task"] for run in RUNS})
def model_options() -> list[str]:
return ["All"] + sorted({run["model"] for run in RUNS})
def condition_options() -> list[str]:
return ["All"] + sorted({run["condition"] for run in RUNS})
def matching_runs(task: str, model: str, condition: str) -> list[dict]:
return [
run
for run in RUNS
if (task == "All" or run["task"] == task)
and (model == "All" or run["model"] == model)
and (condition == "All" or run["condition"] == condition)
]
def run_label(run: dict) -> str:
condition = CONDITION_LABELS.get(run["condition"], run["condition"])
return f"{run['task']} | {run['model']} | {condition} | {score_label(run.get('mean_score'))}"
def summary_rows() -> list[list[str]]:
rows = []
for run in RUNS:
rows.append(
[
run["task"],
run["model"],
CONDITION_LABELS.get(run["condition"], run["condition"]),
score_label(run.get("mean_score")),
str(run.get("num_episodes", "")),
run.get("hf_eval_dataset_id") or "",
]
)
return rows
def update_run_choices(task: str, model: str, condition: str):
runs = matching_runs(task, model, condition)
choices = [run_label(run) for run in runs]
value = choices[0] if choices else None
max_episode = runs[0]["num_episodes"] if runs else 1
return (
gr.update(choices=choices, value=value),
gr.update(minimum=1, maximum=max_episode, value=1),
)
def selected_run(label: str | None) -> dict | None:
if not label:
return None
for run in RUNS:
if run_label(run) == label:
return run
return None
def render_episode(run_choice: str | None, episode_number: int):
run = selected_run(run_choice)
if run is None:
return None, None, "No run selected.", "No trajectory input."
episode_number = int(episode_number)
episodes = run["episodes"]
episode = next((ep for ep in episodes if ep["episode_number"] == episode_number), episodes[0])
video = episode.get("video")
overlay = episode.get("overlay")
if overlay:
overlay = str(ROOT / overlay)
if run["condition"] == "specialist":
trajectory_text = "Specialist baseline: no trajectory sketch or dataset trajectory was provided."
elif episode.get("trajectory_source_mode") == "dataset":
trajectory_text = f"Dataset trajectory from source episode {episode.get('trajectory_source_episode')}."
elif episode.get("trajectory_source_mode") == "draw":
trajectory_text = "Drawn trajectory input."
else:
trajectory_text = "Trajectory metadata unavailable."
comment = episode.get("comment") or ""
error = episode.get("episode_error") or ""
details = "\n".join(
line
for line in [
f"Task: {run['task']}",
f"Model: {run['model']}",
f"Condition: {CONDITION_LABELS.get(run['condition'], run['condition'])}",
f"Run: {run.get('run_id')}",
f"Episode: {episode.get('episode_number')}",
f"Score: {score_label(episode.get('score'))}",
f"Dataset: {run.get('hf_eval_dataset_id')}",
f"Comment: {comment}" if comment else "",
f"Error: {error}" if error else "",
episode.get("video_note") or "The video is the full LeRobot chunk for this run. Use the slider to change the overlay image to the current dataset episode.",
"Video unavailable in manifest." if not video else "",
]
if line
)
return video, overlay, details, trajectory_text
def update_episode_bounds(run_choice: str | None):
run = selected_run(run_choice)
max_episode = run["num_episodes"] if run else 1
return gr.update(minimum=1, maximum=max_episode, value=1)
css = """
.main-header h1 { margin-bottom: 0.25rem; }
.main-header p { margin-top: 0; color: #475569; }
textarea { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
"""
with gr.Blocks(title=MANIFEST.get("title", "Trajectory Showcase")) as demo:
gr.Markdown(
f"""
<div class="main-header">
<h1>{MANIFEST.get("title", "Diffusion Trajectory Model Showcase")}</h1>
<p>Episode-level videos, trajectory inputs, and scores generated from experiment logs.</p>
</div>
"""
)
gr.Dataframe(
headers=["Task", "Model", "Condition", "Mean score", "Episodes", "Dataset"],
value=summary_rows(),
interactive=False,
wrap=True,
)
with gr.Row():
task_filter = gr.Dropdown(task_options(), value="All", label="Task")
model_filter = gr.Dropdown(model_options(), value="All", label="Model")
condition_filter = gr.Dropdown(condition_options(), value="All", label="Condition")
initial_runs = matching_runs("All", "All", "All")
run_select = gr.Dropdown(
[run_label(run) for run in initial_runs],
value=run_label(initial_runs[0]) if initial_runs else None,
label="Run",
)
episode_slider = gr.Slider(
minimum=1,
maximum=initial_runs[0]["num_episodes"] if initial_runs else 1,
value=1,
step=1,
label="Episode",
)
gr.Markdown("Use the slider to change the overlay image to the current dataset episode.")
with gr.Row():
video = gr.Video(label="Result video")
overlay = gr.Image(label="Trajectory input", type="filepath")
trajectory_text = gr.Textbox(label="Trajectory source", interactive=False)
details = gr.Textbox(label="Episode metadata", lines=10, interactive=False)
for control in (task_filter, model_filter, condition_filter):
control.change(
update_run_choices,
inputs=[task_filter, model_filter, condition_filter],
outputs=[run_select, episode_slider],
).then(render_episode, inputs=[run_select, episode_slider], outputs=[video, overlay, details, trajectory_text])
run_select.change(update_episode_bounds, inputs=run_select, outputs=episode_slider).then(
render_episode,
inputs=[run_select, episode_slider],
outputs=[video, overlay, details, trajectory_text],
)
episode_slider.change(
render_episode,
inputs=[run_select, episode_slider],
outputs=[video, overlay, details, trajectory_text],
)
demo.load(render_episode, inputs=[run_select, episode_slider], outputs=[video, overlay, details, trajectory_text])
if __name__ == "__main__":
demo.launch(css=css)