Spaces:
Sleeping
Sleeping
| """Hugging Face Gradio Space for state-conditioned π₀.₅ UR inference.""" | |
| from __future__ import annotations | |
| import gc | |
| try: | |
| import gradio as gr | |
| except ImportError: # Core inference tests can run without the UI dependency. | |
| gr = None | |
| try: | |
| import spaces | |
| except ImportError: # Local and dedicated-GPU environments omit this helper. | |
| class _SpacesFallback: | |
| def GPU(*args, **kwargs): | |
| return lambda function: function | |
| spaces = _SpacesFallback() | |
| from artifacts import download_checkpoint, resolve_checkpoint_path, resolve_model_id | |
| from inference import ACTION_LABELS, run_prediction | |
| from model_loader import DEFAULT_POLICY_CONFIG, MODEL_MANAGER, POLICY_CONFIGS | |
| def prefetch_configured_checkpoint() -> str: | |
| """Download and validate configured weights during Space startup, before GPU use.""" | |
| model_id = resolve_model_id() | |
| if not model_id: | |
| return "No PI05_MODEL_ID configured; download will occur on first prediction." | |
| checkpoint_path = resolve_checkpoint_path() | |
| paths = download_checkpoint(model_id, checkpoint_path) | |
| return f"Checkpoint ready: {model_id}/{checkpoint_path} ({paths.norm_stats.name})." | |
| def _gradio_integer(value, name: str) -> int: | |
| if isinstance(value, bool) or not isinstance(value, (int, float)): | |
| raise ValueError(f"{name} must be an integer") | |
| if not float(value).is_integer(): | |
| raise ValueError(f"{name} must be an integer") | |
| result = int(value) | |
| if result < 0: | |
| raise ValueError(f"{name} must be non-negative") | |
| return result | |
| def predict_ui( | |
| model_id, | |
| checkpoint_path, | |
| config_name, | |
| fixed_image, | |
| wrist_image, | |
| instruction, | |
| tcp_x, | |
| tcp_y, | |
| tcp_z, | |
| tcp_roll, | |
| tcp_pitch, | |
| tcp_yaw, | |
| gripper, | |
| trial_index, | |
| ): | |
| try: | |
| trial = _gradio_integer(trial_index, "trial index") | |
| policy = MODEL_MANAGER.get(model_id, checkpoint_path, config_name) | |
| result = run_prediction( | |
| policy, | |
| fixed_image, | |
| wrist_image, | |
| instruction, | |
| [tcp_x, tcp_y, tcp_z, tcp_roll, tcp_pitch, tcp_yaw, gripper], | |
| trial, | |
| model_id, | |
| checkpoint_path, | |
| ) | |
| uses_discrete_state = config_name == "pi05_ur_demo_state" | |
| status = ( | |
| f"{result.status} Config={config_name} " | |
| f"(discrete_state_input={uses_discrete_state})." | |
| ) | |
| return result.actions, result.json_path, status | |
| except Exception as exc: | |
| gc.collect() | |
| try: | |
| import torch | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| except ImportError: | |
| pass | |
| return None, None, f"Error: {exc}" | |
| def build_demo(): | |
| if gr is None: | |
| return None | |
| with gr.Blocks(title="π₀.₅ UR Action Predictor") as demo: | |
| gr.Markdown( | |
| "# π₀.₅ UR Action Predictor\n" | |
| "forked from , thx!" | |
| "Upload the fixed and wrist camera views, enter the current TCP/gripper " | |
| "state and a task instruction. This demo predicts actions only and does " | |
| "not directly control a robot." | |
| ) | |
| with gr.Row(): | |
| model_id = gr.Textbox( | |
| value=resolve_model_id(), | |
| label="Hugging Face model ID", | |
| placeholder="owner/pi05-ur-checkpoint", | |
| ) | |
| checkpoint_path = gr.Textbox( | |
| value=resolve_checkpoint_path(), | |
| label="Checkpoint path", | |
| placeholder="checkpoints/30000", | |
| ) | |
| config_name = gr.Dropdown( | |
| choices=list(POLICY_CONFIGS), | |
| value=DEFAULT_POLICY_CONFIG, | |
| label="Policy config", | |
| ) | |
| with gr.Row(): | |
| fixed_image = gr.Image(type="pil", label="Fixed camera") | |
| wrist_image = gr.Image(type="pil", label="Wrist camera") | |
| instruction = gr.Textbox( | |
| label="Task instruction", | |
| placeholder="e.g. pick up the object and place it in the tray", | |
| lines=2, | |
| ) | |
| gr.Markdown( | |
| "### Current state — metres/radians, followed by gripper state\n" | |
| "These values are discrete state conditioning only when " | |
| "`pi05_ur_demo_state` is selected." | |
| ) | |
| with gr.Row(): | |
| tcp_x = gr.Number(value=0.0, label="TCP x") | |
| tcp_y = gr.Number(value=0.0, label="TCP y") | |
| tcp_z = gr.Number(value=0.0, label="TCP z") | |
| tcp_roll = gr.Number(value=0.0, label="TCP roll") | |
| gr.Markdown("哈基米") | |
| with gr.Row(): | |
| tcp_pitch = gr.Number(value=0.0, label="TCP pitch") | |
| tcp_yaw = gr.Number(value=0.0, label="TCP yaw") | |
| gripper = gr.Number(value=0.0, label="Gripper") | |
| trial_index = gr.Number(value=0, precision=0, minimum=0, label="Trial index") | |
| predict_button = gr.Button("Predict actions", variant="primary") | |
| status = gr.Markdown(STARTUP_STATUS) | |
| actions = gr.Dataframe(headers=list(ACTION_LABELS), interactive=False, label="Predicted actions") | |
| json_output = gr.File(label="Download JSON result") | |
| predict_button.click( | |
| fn=predict_ui, | |
| inputs=[ | |
| model_id, | |
| checkpoint_path, | |
| config_name, | |
| fixed_image, | |
| wrist_image, | |
| instruction, | |
| tcp_x, | |
| tcp_y, | |
| tcp_z, | |
| tcp_roll, | |
| tcp_pitch, | |
| tcp_yaw, | |
| gripper, | |
| trial_index, | |
| ], | |
| outputs=[actions, json_output, status], | |
| ) | |
| return demo | |
| # Hugging Face Spaces imports app.py during startup. Prefetching here moves the | |
| # multi-GB download out of the GPU-decorated prediction request when env vars are set. | |
| try: | |
| STARTUP_STATUS = prefetch_configured_checkpoint() | |
| except Exception as exc: | |
| STARTUP_STATUS = f"Checkpoint prefetch deferred: {exc}" | |
| demo = build_demo() | |
| if __name__ == "__main__": | |
| if demo is None: | |
| raise RuntimeError("Gradio is not installed; install requirements.txt first") | |
| demo.queue(default_concurrency_limit=1).launch() | |