multimodalart HF Staff commited on
Commit
7de5fac
·
verified ·
1 Parent(s): a878f73

Fix NaN state input on gr.Examples click; use gr.JSON output with rounded values

Browse files
Files changed (1) hide show
  1. app.py +39 -13
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 string with the raw action values.
242
  """
243
  if not instruction or not instruction.strip():
244
- return None, '{"error": "Please provide a task instruction."}'
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, json.dumps(result, indent=2)
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.Textbox(label="Action Details (JSON)", lines=12, max_lines=20)
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=[