Spaces:
Running on Zero
Running on Zero
Fix NaN state input on gr.Examples click; use gr.JSON output with rounded values
Browse files
app.py
CHANGED
|
@@ -216,13 +216,22 @@ def build_batch(images, prompt, state):
|
|
| 216 |
return batch
|
| 217 |
|
| 218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
@spaces.GPU(duration=120)
|
| 220 |
def predict_actions(
|
| 221 |
camera_1: Image.Image,
|
| 222 |
instruction: str,
|
| 223 |
-
state_j1: float, state_j2: float, state_j3: float,
|
| 224 |
-
state_j4: float, state_j5: float, state_j6: float,
|
| 225 |
-
state_j7: float, gripper: float,
|
| 226 |
):
|
| 227 |
"""Predict a robot action chunk from laboratory camera views and a language instruction.
|
| 228 |
|
|
@@ -233,15 +242,15 @@ def predict_actions(
|
|
| 233 |
Args:
|
| 234 |
camera_1: Camera view of the laboratory workspace.
|
| 235 |
instruction: Natural language task instruction (e.g. "Pick up the beaker").
|
| 236 |
-
state_j1..j7: Franka Panda 7-DOF arm joint angles (radians).
|
| 237 |
-
gripper: Gripper width in meters (0.0 = closed, 0.04 = fully open).
|
| 238 |
|
| 239 |
Returns:
|
| 240 |
A matplotlib figure visualizing the predicted action trajectory,
|
| 241 |
-
and a JSON
|
| 242 |
"""
|
| 243 |
if not instruction or not instruction.strip():
|
| 244 |
-
return None,
|
| 245 |
|
| 246 |
# Convert PIL image to numpy
|
| 247 |
img1 = np.array(camera_1.convert("RGB"))
|
|
@@ -251,6 +260,20 @@ def predict_actions(
|
|
| 251 |
# with only 1, slots 2/3 are masked out)
|
| 252 |
images = [img1, None, None]
|
| 253 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
# Build state vector
|
| 255 |
state = np.array([state_j1, state_j2, state_j3, state_j4,
|
| 256 |
state_j5, state_j6, state_j7, gripper], dtype=np.float32)
|
|
@@ -322,20 +345,23 @@ def predict_actions(
|
|
| 322 |
fig.savefig(fig_path, dpi=150, bbox_inches="tight")
|
| 323 |
plt.close(fig)
|
| 324 |
|
| 325 |
-
# Prepare JSON output
|
|
|
|
|
|
|
|
|
|
| 326 |
actions_list = actions.tolist()
|
| 327 |
result = {
|
| 328 |
"instruction": instruction,
|
| 329 |
-
"state_input": state.tolist(),
|
| 330 |
"action_chunk_shape": list(actions.shape),
|
| 331 |
"num_steps": int(actions.shape[0]),
|
| 332 |
"action_dim": int(actions.shape[1]),
|
| 333 |
"inference_time_s": round(infer_time, 3),
|
| 334 |
-
"first_action": actions_list[0] if len(actions_list) > 0 else None,
|
| 335 |
-
"last_action": actions_list[-1] if len(actions_list) > 0 else None,
|
| 336 |
}
|
| 337 |
|
| 338 |
-
return fig_path,
|
| 339 |
|
| 340 |
|
| 341 |
# ---- Gradio UI ----
|
|
@@ -390,7 +416,7 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
|
|
| 390 |
|
| 391 |
with gr.Column(scale=1):
|
| 392 |
output_plot = gr.Image(label="Predicted Action Trajectory (50 steps)")
|
| 393 |
-
output_json = gr.
|
| 394 |
|
| 395 |
gr.Examples(
|
| 396 |
examples=[
|
|
|
|
| 216 |
return batch
|
| 217 |
|
| 218 |
|
| 219 |
+
# Default robot state used whenever a caller doesn't provide one (e.g. the
|
| 220 |
+
# gr.Examples rows below only populate camera_1 + instruction). This mirrors
|
| 221 |
+
# the default values of the Robot State sliders in the UI, so results are
|
| 222 |
+
# consistent regardless of entry point (example click, manual button click,
|
| 223 |
+
# or a direct API call that omits the state args).
|
| 224 |
+
DEFAULT_STATE_J = 0.0
|
| 225 |
+
DEFAULT_GRIPPER = 0.04
|
| 226 |
+
|
| 227 |
+
|
| 228 |
@spaces.GPU(duration=120)
|
| 229 |
def predict_actions(
|
| 230 |
camera_1: Image.Image,
|
| 231 |
instruction: str,
|
| 232 |
+
state_j1: float = DEFAULT_STATE_J, state_j2: float = DEFAULT_STATE_J, state_j3: float = DEFAULT_STATE_J,
|
| 233 |
+
state_j4: float = DEFAULT_STATE_J, state_j5: float = DEFAULT_STATE_J, state_j6: float = DEFAULT_STATE_J,
|
| 234 |
+
state_j7: float = DEFAULT_STATE_J, gripper: float = DEFAULT_GRIPPER,
|
| 235 |
):
|
| 236 |
"""Predict a robot action chunk from laboratory camera views and a language instruction.
|
| 237 |
|
|
|
|
| 242 |
Args:
|
| 243 |
camera_1: Camera view of the laboratory workspace.
|
| 244 |
instruction: Natural language task instruction (e.g. "Pick up the beaker").
|
| 245 |
+
state_j1..j7: Franka Panda 7-DOF arm joint angles (radians). Defaults to 0.0.
|
| 246 |
+
gripper: Gripper width in meters (0.0 = closed, 0.04 = fully open). Defaults to 0.04.
|
| 247 |
|
| 248 |
Returns:
|
| 249 |
A matplotlib figure visualizing the predicted action trajectory,
|
| 250 |
+
and a JSON dict with the raw action values.
|
| 251 |
"""
|
| 252 |
if not instruction or not instruction.strip():
|
| 253 |
+
return None, {"error": "Please provide a task instruction."}
|
| 254 |
|
| 255 |
# Convert PIL image to numpy
|
| 256 |
img1 = np.array(camera_1.convert("RGB"))
|
|
|
|
| 260 |
# with only 1, slots 2/3 are masked out)
|
| 261 |
images = [img1, None, None]
|
| 262 |
|
| 263 |
+
# Guard against any caller (or gr.Examples cache) passing an empty/missing
|
| 264 |
+
# value for a state component. NaN must never reach the model.
|
| 265 |
+
def _clean(value, default):
|
| 266 |
+
return default if value is None else value
|
| 267 |
+
|
| 268 |
+
state_j1 = _clean(state_j1, DEFAULT_STATE_J)
|
| 269 |
+
state_j2 = _clean(state_j2, DEFAULT_STATE_J)
|
| 270 |
+
state_j3 = _clean(state_j3, DEFAULT_STATE_J)
|
| 271 |
+
state_j4 = _clean(state_j4, DEFAULT_STATE_J)
|
| 272 |
+
state_j5 = _clean(state_j5, DEFAULT_STATE_J)
|
| 273 |
+
state_j6 = _clean(state_j6, DEFAULT_STATE_J)
|
| 274 |
+
state_j7 = _clean(state_j7, DEFAULT_STATE_J)
|
| 275 |
+
gripper = _clean(gripper, DEFAULT_GRIPPER)
|
| 276 |
+
|
| 277 |
# Build state vector
|
| 278 |
state = np.array([state_j1, state_j2, state_j3, state_j4,
|
| 279 |
state_j5, state_j6, state_j7, gripper], dtype=np.float32)
|
|
|
|
| 345 |
fig.savefig(fig_path, dpi=150, bbox_inches="tight")
|
| 346 |
plt.close(fig)
|
| 347 |
|
| 348 |
+
# Prepare JSON output (rounded for readability; gr.JSON renders the dict natively)
|
| 349 |
+
def _round_list(values, ndigits=4):
|
| 350 |
+
return [round(float(v), ndigits) for v in values]
|
| 351 |
+
|
| 352 |
actions_list = actions.tolist()
|
| 353 |
result = {
|
| 354 |
"instruction": instruction,
|
| 355 |
+
"state_input": _round_list(state.tolist()),
|
| 356 |
"action_chunk_shape": list(actions.shape),
|
| 357 |
"num_steps": int(actions.shape[0]),
|
| 358 |
"action_dim": int(actions.shape[1]),
|
| 359 |
"inference_time_s": round(infer_time, 3),
|
| 360 |
+
"first_action": _round_list(actions_list[0]) if len(actions_list) > 0 else None,
|
| 361 |
+
"last_action": _round_list(actions_list[-1]) if len(actions_list) > 0 else None,
|
| 362 |
}
|
| 363 |
|
| 364 |
+
return fig_path, result
|
| 365 |
|
| 366 |
|
| 367 |
# ---- Gradio UI ----
|
|
|
|
| 416 |
|
| 417 |
with gr.Column(scale=1):
|
| 418 |
output_plot = gr.Image(label="Predicted Action Trajectory (50 steps)")
|
| 419 |
+
output_json = gr.JSON(label="Action Details (JSON)")
|
| 420 |
|
| 421 |
gr.Examples(
|
| 422 |
examples=[
|