system log executing!
Browse files
gradio-web/config.py
CHANGED
|
@@ -65,6 +65,7 @@ UI_TEXT = {
|
|
| 65 |
"log": {
|
| 66 |
"action_selection_prompt": "Please select the action.\nActions with 🎯 need to select a point on the image as input",
|
| 67 |
"point_selection_prompt": "Current action needs location input, please click on the image to select key pixel",
|
|
|
|
| 68 |
"demo_video_prompt": 'Press "Watch Video Input 🎬" to watch a video\nNote: you can only watch the video once',
|
| 69 |
"session_error": "Session expired. Please refresh the page and try again.",
|
| 70 |
"reference_action_error": "Ground Truth Action Error: {error}",
|
|
|
|
| 65 |
"log": {
|
| 66 |
"action_selection_prompt": "Please select the action.\nActions with 🎯 need to select a point on the image as input",
|
| 67 |
"point_selection_prompt": "Current action needs location input, please click on the image to select key pixel",
|
| 68 |
+
"execute_action_prompt": "Executing Action {label}",
|
| 69 |
"demo_video_prompt": 'Press "Watch Video Input 🎬" to watch a video\nNote: you can only watch the video once',
|
| 70 |
"session_error": "Session expired. Please refresh the page and try again.",
|
| 71 |
"reference_action_error": "Ground Truth Action Error: {error}",
|
gradio-web/gradio_callbacks.py
CHANGED
|
@@ -62,10 +62,41 @@ def _point_selection_log():
|
|
| 62 |
return format_log_markdown(_ui_text("log", "point_selection_prompt"))
|
| 63 |
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
def _default_post_execute_log_state():
|
| 66 |
return {
|
| 67 |
"preserve_terminal_log": False,
|
| 68 |
"terminal_log_value": None,
|
|
|
|
|
|
|
| 69 |
}
|
| 70 |
|
| 71 |
|
|
@@ -78,9 +109,17 @@ def _normalize_post_execute_log_state(state):
|
|
| 78 |
preserve_terminal_log = False
|
| 79 |
else:
|
| 80 |
terminal_log_value = str(terminal_log_value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
return {
|
| 82 |
"preserve_terminal_log": preserve_terminal_log,
|
| 83 |
"terminal_log_value": terminal_log_value,
|
|
|
|
|
|
|
| 84 |
}
|
| 85 |
return _default_post_execute_log_state()
|
| 86 |
|
|
@@ -487,9 +526,11 @@ def on_execute_video_end_transition(
|
|
| 487 |
"""Transition from execute video phase back to the action phase."""
|
| 488 |
controls_state = _normalize_post_execute_controls_state(post_execute_controls_state)
|
| 489 |
log_state = _normalize_post_execute_log_state(post_execute_log_state)
|
| 490 |
-
|
|
|
|
| 491 |
if log_state["preserve_terminal_log"]:
|
| 492 |
log_update = gr.update(value=log_state["terminal_log_value"])
|
|
|
|
| 493 |
LOGGER.debug(
|
| 494 |
"on_execute_video_end_transition uid=%s controls_state=%s log_state=%s",
|
| 495 |
_uid_for_log(uid),
|
|
@@ -508,6 +549,7 @@ def on_execute_video_end_transition(
|
|
| 508 |
log_update, # log_output
|
| 509 |
gr.update(interactive=controls_state["reference_action_interactive"]), # reference_action_btn
|
| 510 |
gr.update(interactive=True), # task_hint_display
|
|
|
|
| 511 |
"action_point", # ui_phase_state
|
| 512 |
)
|
| 513 |
|
|
@@ -928,6 +970,20 @@ def on_option_select(
|
|
| 928 |
False,
|
| 929 |
normalized_post_execute_log_state,
|
| 930 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 931 |
|
| 932 |
if option_value is None:
|
| 933 |
LOGGER.debug("on_option_select uid=%s option=None", _uid_for_log(uid))
|
|
@@ -1445,10 +1501,20 @@ def execute_step(uid, option_idx, coords_str):
|
|
| 1445 |
|
| 1446 |
# 格式化日志消息为 HTML 格式(支持颜色显示)
|
| 1447 |
formatted_status = format_log_markdown(status)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1448 |
if done:
|
| 1449 |
post_execute_log_state = {
|
| 1450 |
"preserve_terminal_log": True,
|
| 1451 |
"terminal_log_value": formatted_status,
|
|
|
|
|
|
|
| 1452 |
}
|
| 1453 |
LOGGER.debug(
|
| 1454 |
"execute_step done uid=%s env=%s ep=%s done=%s post_execute_controls=%s post_execute_log=%s show_execution_video=%s",
|
|
|
|
| 62 |
return format_log_markdown(_ui_text("log", "point_selection_prompt"))
|
| 63 |
|
| 64 |
|
| 65 |
+
def _get_raw_option_label(session, option_idx):
|
| 66 |
+
try:
|
| 67 |
+
option_index = int(option_idx)
|
| 68 |
+
except (TypeError, ValueError):
|
| 69 |
+
return None
|
| 70 |
+
|
| 71 |
+
raw_solve_options = getattr(session, "raw_solve_options", None)
|
| 72 |
+
if not isinstance(raw_solve_options, list):
|
| 73 |
+
return None
|
| 74 |
+
if not (0 <= option_index < len(raw_solve_options)):
|
| 75 |
+
return None
|
| 76 |
+
|
| 77 |
+
raw_option = raw_solve_options[option_index]
|
| 78 |
+
if not isinstance(raw_option, dict):
|
| 79 |
+
return None
|
| 80 |
+
|
| 81 |
+
label = str(raw_option.get("label", "")).strip()
|
| 82 |
+
return label or None
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _execution_video_log(session, option_idx, fallback_status=None):
|
| 86 |
+
label = _get_raw_option_label(session, option_idx)
|
| 87 |
+
if label:
|
| 88 |
+
return format_log_markdown(_ui_text("log", "execute_action_prompt", label=label))
|
| 89 |
+
if fallback_status is None:
|
| 90 |
+
return None
|
| 91 |
+
return format_log_markdown(fallback_status)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
def _default_post_execute_log_state():
|
| 95 |
return {
|
| 96 |
"preserve_terminal_log": False,
|
| 97 |
"terminal_log_value": None,
|
| 98 |
+
"preserve_execute_video_log": False,
|
| 99 |
+
"execute_video_log_value": None,
|
| 100 |
}
|
| 101 |
|
| 102 |
|
|
|
|
| 109 |
preserve_terminal_log = False
|
| 110 |
else:
|
| 111 |
terminal_log_value = str(terminal_log_value)
|
| 112 |
+
preserve_execute_video_log = bool(state.get("preserve_execute_video_log", False))
|
| 113 |
+
execute_video_log_value = state.get("execute_video_log_value")
|
| 114 |
+
if execute_video_log_value is None:
|
| 115 |
+
preserve_execute_video_log = False
|
| 116 |
+
else:
|
| 117 |
+
execute_video_log_value = str(execute_video_log_value)
|
| 118 |
return {
|
| 119 |
"preserve_terminal_log": preserve_terminal_log,
|
| 120 |
"terminal_log_value": terminal_log_value,
|
| 121 |
+
"preserve_execute_video_log": preserve_execute_video_log,
|
| 122 |
+
"execute_video_log_value": execute_video_log_value,
|
| 123 |
}
|
| 124 |
return _default_post_execute_log_state()
|
| 125 |
|
|
|
|
| 526 |
"""Transition from execute video phase back to the action phase."""
|
| 527 |
controls_state = _normalize_post_execute_controls_state(post_execute_controls_state)
|
| 528 |
log_state = _normalize_post_execute_log_state(post_execute_log_state)
|
| 529 |
+
next_log_state = _default_post_execute_log_state()
|
| 530 |
+
log_update = gr.update(value=_action_selection_log())
|
| 531 |
if log_state["preserve_terminal_log"]:
|
| 532 |
log_update = gr.update(value=log_state["terminal_log_value"])
|
| 533 |
+
next_log_state = log_state
|
| 534 |
LOGGER.debug(
|
| 535 |
"on_execute_video_end_transition uid=%s controls_state=%s log_state=%s",
|
| 536 |
_uid_for_log(uid),
|
|
|
|
| 549 |
log_update, # log_output
|
| 550 |
gr.update(interactive=controls_state["reference_action_interactive"]), # reference_action_btn
|
| 551 |
gr.update(interactive=True), # task_hint_display
|
| 552 |
+
next_log_state, # post_execute_log_state
|
| 553 |
"action_point", # ui_phase_state
|
| 554 |
)
|
| 555 |
|
|
|
|
| 970 |
False,
|
| 971 |
normalized_post_execute_log_state,
|
| 972 |
)
|
| 973 |
+
|
| 974 |
+
if normalized_post_execute_log_state["preserve_execute_video_log"]:
|
| 975 |
+
LOGGER.debug(
|
| 976 |
+
"on_option_select preserving execution-video log uid=%s option=%s",
|
| 977 |
+
_uid_for_log(uid),
|
| 978 |
+
option_value,
|
| 979 |
+
)
|
| 980 |
+
return (
|
| 981 |
+
gr.update(),
|
| 982 |
+
gr.update(),
|
| 983 |
+
gr.update(value=normalized_post_execute_log_state["execute_video_log_value"]),
|
| 984 |
+
False,
|
| 985 |
+
normalized_post_execute_log_state,
|
| 986 |
+
)
|
| 987 |
|
| 988 |
if option_value is None:
|
| 989 |
LOGGER.debug("on_option_select uid=%s option=None", _uid_for_log(uid))
|
|
|
|
| 1501 |
|
| 1502 |
# 格式化日志消息为 HTML 格式(支持颜色显示)
|
| 1503 |
formatted_status = format_log_markdown(status)
|
| 1504 |
+
if show_execution_video and not done:
|
| 1505 |
+
formatted_status = _execution_video_log(session, option_idx, fallback_status=status) or formatted_status
|
| 1506 |
+
post_execute_log_state = {
|
| 1507 |
+
"preserve_terminal_log": False,
|
| 1508 |
+
"terminal_log_value": None,
|
| 1509 |
+
"preserve_execute_video_log": True,
|
| 1510 |
+
"execute_video_log_value": formatted_status,
|
| 1511 |
+
}
|
| 1512 |
if done:
|
| 1513 |
post_execute_log_state = {
|
| 1514 |
"preserve_terminal_log": True,
|
| 1515 |
"terminal_log_value": formatted_status,
|
| 1516 |
+
"preserve_execute_video_log": False,
|
| 1517 |
+
"execute_video_log_value": None,
|
| 1518 |
}
|
| 1519 |
LOGGER.debug(
|
| 1520 |
"execute_step done uid=%s env=%s ep=%s done=%s post_execute_controls=%s post_execute_log=%s show_execution_video=%s",
|
gradio-web/test/test_live_obs_refresh.py
CHANGED
|
@@ -7,7 +7,7 @@ class _FakeSession:
|
|
| 7 |
def __init__(self):
|
| 8 |
self.env_id = "BinFill"
|
| 9 |
self.episode_idx = 1
|
| 10 |
-
self.raw_solve_options = [{"available": False}]
|
| 11 |
self.available_options = [("pick", 0)]
|
| 12 |
self.base_frames = []
|
| 13 |
self.last_execution_frames = []
|
|
@@ -63,8 +63,19 @@ def test_execute_step_builds_video_from_last_execution_frames(monkeypatch, reloa
|
|
| 63 |
assert result[11]["value"] is None
|
| 64 |
assert result[11]["interactive"] is False
|
| 65 |
assert result[14]["interactive"] is False
|
| 66 |
-
|
| 67 |
-
assert result[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
|
| 70 |
def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeypatch, reload_module):
|
|
@@ -98,7 +109,7 @@ def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeyp
|
|
| 98 |
assert int(captured["frames"][0][0, 0, 0]) == 33
|
| 99 |
assert result[7]["visible"] is True
|
| 100 |
assert result[10]["visible"] is True
|
| 101 |
-
assert result[
|
| 102 |
|
| 103 |
|
| 104 |
def test_switch_phase_toggles_live_obs_interactive_without_refresh_queue(reload_module):
|
|
|
|
| 7 |
def __init__(self):
|
| 8 |
self.env_id = "BinFill"
|
| 9 |
self.episode_idx = 1
|
| 10 |
+
self.raw_solve_options = [{"label": "a", "available": False}]
|
| 11 |
self.available_options = [("pick", 0)]
|
| 12 |
self.base_frames = []
|
| 13 |
self.last_execution_frames = []
|
|
|
|
| 63 |
assert result[11]["value"] is None
|
| 64 |
assert result[11]["interactive"] is False
|
| 65 |
assert result[14]["interactive"] is False
|
| 66 |
+
expected_log = callbacks.UI_TEXT["log"]["execute_action_prompt"].format(label="a")
|
| 67 |
+
assert result[1] == expected_log
|
| 68 |
+
assert result[15] == {
|
| 69 |
+
"exec_btn_interactive": True,
|
| 70 |
+
"reference_action_interactive": True,
|
| 71 |
+
}
|
| 72 |
+
assert result[16] == {
|
| 73 |
+
"preserve_terminal_log": False,
|
| 74 |
+
"terminal_log_value": None,
|
| 75 |
+
"preserve_execute_video_log": True,
|
| 76 |
+
"execute_video_log_value": expected_log,
|
| 77 |
+
}
|
| 78 |
+
assert result[17] == "execution_video"
|
| 79 |
|
| 80 |
|
| 81 |
def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeypatch, reload_module):
|
|
|
|
| 109 |
assert int(captured["frames"][0][0, 0, 0]) == 33
|
| 110 |
assert result[7]["visible"] is True
|
| 111 |
assert result[10]["visible"] is True
|
| 112 |
+
assert result[17] == "execution_video"
|
| 113 |
|
| 114 |
|
| 115 |
def test_switch_phase_toggles_live_obs_interactive_without_refresh_queue(reload_module):
|
gradio-web/test/test_ui_phase_machine_runtime_e2e.py
CHANGED
|
@@ -2576,7 +2576,10 @@ def _run_local_execute_video_transition_test(
|
|
| 2576 |
self.episode_idx = 1
|
| 2577 |
self.language_goal = "place cube on target"
|
| 2578 |
self.available_options = [("pick", 0), ("point", 1)]
|
| 2579 |
-
self.raw_solve_options = [
|
|
|
|
|
|
|
|
|
|
| 2580 |
self.demonstration_frames = []
|
| 2581 |
self.last_execution_frames = []
|
| 2582 |
self.base_frames = [fake_obs.copy()]
|
|
@@ -2624,6 +2627,8 @@ def _run_local_execute_video_transition_test(
|
|
| 2624 |
value={
|
| 2625 |
"preserve_terminal_log": False,
|
| 2626 |
"terminal_log_value": None,
|
|
|
|
|
|
|
| 2627 |
}
|
| 2628 |
)
|
| 2629 |
suppress_state = gr.State(value=False)
|
|
@@ -2705,6 +2710,12 @@ def _run_local_execute_video_transition_test(
|
|
| 2705 |
outputs=[coords_box, img_display, log_output, suppress_state, post_execute_log_state],
|
| 2706 |
queue=False,
|
| 2707 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2708 |
|
| 2709 |
execute_video_display.end(
|
| 2710 |
fn=cb.on_execute_video_end_transition,
|
|
@@ -2721,6 +2732,7 @@ def _run_local_execute_video_transition_test(
|
|
| 2721 |
log_output,
|
| 2722 |
reference_action_btn,
|
| 2723 |
task_hint_display,
|
|
|
|
| 2724 |
phase_state,
|
| 2725 |
],
|
| 2726 |
queue=False,
|
|
@@ -2740,6 +2752,7 @@ def _run_local_execute_video_transition_test(
|
|
| 2740 |
log_output,
|
| 2741 |
reference_action_btn,
|
| 2742 |
task_hint_display,
|
|
|
|
| 2743 |
phase_state,
|
| 2744 |
],
|
| 2745 |
queue=False,
|
|
@@ -2764,7 +2777,39 @@ def _run_local_execute_video_transition_test(
|
|
| 2764 |
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
| 2765 |
page.goto(root_url, wait_until="domcontentloaded")
|
| 2766 |
page.wait_for_selector("#main_interface", state="visible", timeout=20000)
|
| 2767 |
-
page.locator("#action_radio input[type='radio']").
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2768 |
page.locator("#exec_btn button, button#exec_btn").first.click()
|
| 2769 |
page.wait_for_selector("#execute_video video", timeout=5000)
|
| 2770 |
page.wait_for_function(
|
|
@@ -2788,6 +2833,10 @@ def _run_local_execute_video_transition_test(
|
|
| 2788 |
}""",
|
| 2789 |
timeout=10000,
|
| 2790 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2791 |
controls_after_execute = _read_demo_video_controls(page, elem_id="execute_video", button_elem_id=None)
|
| 2792 |
assert controls_after_execute["autoplay"] is True
|
| 2793 |
assert controls_after_execute["paused"] is False
|
|
@@ -2881,30 +2930,7 @@ def _run_local_execute_video_transition_test(
|
|
| 2881 |
"execDisabled": False,
|
| 2882 |
"refDisabled": False,
|
| 2883 |
}
|
| 2884 |
-
|
| 2885 |
-
page.wait_for_function(
|
| 2886 |
-
"""(state) => {
|
| 2887 |
-
const liveObs = document.getElementById('live_obs');
|
| 2888 |
-
const coordsRoot = document.getElementById('coords_box');
|
| 2889 |
-
const coordsField = coordsRoot?.querySelector('textarea, input');
|
| 2890 |
-
const logRoot = document.getElementById('log_output');
|
| 2891 |
-
const logField = logRoot?.querySelector('textarea, input');
|
| 2892 |
-
const coordsValue = coordsField ? coordsField.value.trim() : '';
|
| 2893 |
-
const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
|
| 2894 |
-
return (
|
| 2895 |
-
!!liveObs &&
|
| 2896 |
-
liveObs.classList.contains(state.waitClass) &&
|
| 2897 |
-
coordsValue === state.coordsPrompt &&
|
| 2898 |
-
logValue === state.waitLog
|
| 2899 |
-
);
|
| 2900 |
-
}""",
|
| 2901 |
-
arg={
|
| 2902 |
-
"waitClass": config_module.LIVE_OBS_POINT_WAIT_CLASS,
|
| 2903 |
-
"coordsPrompt": config_module.UI_TEXT["coords"]["select_point"],
|
| 2904 |
-
"waitLog": config_module.UI_TEXT["log"]["point_selection_prompt"],
|
| 2905 |
-
},
|
| 2906 |
-
timeout=5000,
|
| 2907 |
-
)
|
| 2908 |
|
| 2909 |
browser.close()
|
| 2910 |
finally:
|
|
@@ -3039,6 +3065,8 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
|
|
| 3039 |
value={
|
| 3040 |
"preserve_terminal_log": False,
|
| 3041 |
"terminal_log_value": None,
|
|
|
|
|
|
|
| 3042 |
}
|
| 3043 |
)
|
| 3044 |
suppress_state = gr.State(value=False)
|
|
@@ -3140,6 +3168,7 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
|
|
| 3140 |
log_output,
|
| 3141 |
reference_action_btn,
|
| 3142 |
task_hint_display,
|
|
|
|
| 3143 |
phase_state,
|
| 3144 |
],
|
| 3145 |
queue=False,
|
|
@@ -3159,6 +3188,7 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
|
|
| 3159 |
log_output,
|
| 3160 |
reference_action_btn,
|
| 3161 |
task_hint_display,
|
|
|
|
| 3162 |
phase_state,
|
| 3163 |
],
|
| 3164 |
queue=False,
|
|
|
|
| 2576 |
self.episode_idx = 1
|
| 2577 |
self.language_goal = "place cube on target"
|
| 2578 |
self.available_options = [("pick", 0), ("point", 1)]
|
| 2579 |
+
self.raw_solve_options = [
|
| 2580 |
+
{"label": "a", "action": "pick", "available": False},
|
| 2581 |
+
{"label": "b", "action": "point", "available": [object()]},
|
| 2582 |
+
]
|
| 2583 |
self.demonstration_frames = []
|
| 2584 |
self.last_execution_frames = []
|
| 2585 |
self.base_frames = [fake_obs.copy()]
|
|
|
|
| 2627 |
value={
|
| 2628 |
"preserve_terminal_log": False,
|
| 2629 |
"terminal_log_value": None,
|
| 2630 |
+
"preserve_execute_video_log": False,
|
| 2631 |
+
"execute_video_log_value": None,
|
| 2632 |
}
|
| 2633 |
)
|
| 2634 |
suppress_state = gr.State(value=False)
|
|
|
|
| 2710 |
outputs=[coords_box, img_display, log_output, suppress_state, post_execute_log_state],
|
| 2711 |
queue=False,
|
| 2712 |
)
|
| 2713 |
+
img_display.select(
|
| 2714 |
+
fn=cb.on_map_click,
|
| 2715 |
+
inputs=[uid_state, options_radio],
|
| 2716 |
+
outputs=[img_display, coords_box, log_output],
|
| 2717 |
+
queue=False,
|
| 2718 |
+
)
|
| 2719 |
|
| 2720 |
execute_video_display.end(
|
| 2721 |
fn=cb.on_execute_video_end_transition,
|
|
|
|
| 2732 |
log_output,
|
| 2733 |
reference_action_btn,
|
| 2734 |
task_hint_display,
|
| 2735 |
+
post_execute_log_state,
|
| 2736 |
phase_state,
|
| 2737 |
],
|
| 2738 |
queue=False,
|
|
|
|
| 2752 |
log_output,
|
| 2753 |
reference_action_btn,
|
| 2754 |
task_hint_display,
|
| 2755 |
+
post_execute_log_state,
|
| 2756 |
phase_state,
|
| 2757 |
],
|
| 2758 |
queue=False,
|
|
|
|
| 2777 |
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
| 2778 |
page.goto(root_url, wait_until="domcontentloaded")
|
| 2779 |
page.wait_for_selector("#main_interface", state="visible", timeout=20000)
|
| 2780 |
+
page.locator("#action_radio input[type='radio']").nth(1).check(force=True)
|
| 2781 |
+
page.wait_for_function(
|
| 2782 |
+
"""(state) => {
|
| 2783 |
+
const coordsRoot = document.getElementById('coords_box');
|
| 2784 |
+
const coordsField = coordsRoot?.querySelector('textarea, input');
|
| 2785 |
+
const logRoot = document.getElementById('log_output');
|
| 2786 |
+
const logField = logRoot?.querySelector('textarea, input');
|
| 2787 |
+
const coordsValue = coordsField ? coordsField.value.trim() : '';
|
| 2788 |
+
const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
|
| 2789 |
+
return coordsValue === state.coordsPrompt && logValue === state.waitLog;
|
| 2790 |
+
}""",
|
| 2791 |
+
arg={
|
| 2792 |
+
"coordsPrompt": config_module.UI_TEXT["coords"]["select_point"],
|
| 2793 |
+
"waitLog": config_module.UI_TEXT["log"]["point_selection_prompt"],
|
| 2794 |
+
},
|
| 2795 |
+
timeout=5000,
|
| 2796 |
+
)
|
| 2797 |
+
box = page.locator("#live_obs img").bounding_box()
|
| 2798 |
+
assert box is not None
|
| 2799 |
+
page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
|
| 2800 |
+
page.wait_for_function(
|
| 2801 |
+
"""(state) => {
|
| 2802 |
+
const coordsRoot = document.getElementById('coords_box');
|
| 2803 |
+
const coordsField = coordsRoot?.querySelector('textarea, input');
|
| 2804 |
+
const logRoot = document.getElementById('log_output');
|
| 2805 |
+
const logField = logRoot?.querySelector('textarea, input');
|
| 2806 |
+
const coordsValue = coordsField ? coordsField.value.trim() : '';
|
| 2807 |
+
const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
|
| 2808 |
+
return /^\\d+\\s*,\\s*\\d+$/.test(coordsValue) && logValue === state.actionLog;
|
| 2809 |
+
}""",
|
| 2810 |
+
arg={"actionLog": config_module.UI_TEXT["log"]["action_selection_prompt"]},
|
| 2811 |
+
timeout=5000,
|
| 2812 |
+
)
|
| 2813 |
page.locator("#exec_btn button, button#exec_btn").first.click()
|
| 2814 |
page.wait_for_selector("#execute_video video", timeout=5000)
|
| 2815 |
page.wait_for_function(
|
|
|
|
| 2833 |
}""",
|
| 2834 |
timeout=10000,
|
| 2835 |
)
|
| 2836 |
+
if not done:
|
| 2837 |
+
execution_log = _read_log_output_value(page)
|
| 2838 |
+
assert execution_log == config_module.UI_TEXT["log"]["execute_action_prompt"].format(label="b")
|
| 2839 |
+
assert execution_log != config_module.UI_TEXT["log"]["point_selection_prompt"]
|
| 2840 |
controls_after_execute = _read_demo_video_controls(page, elem_id="execute_video", button_elem_id=None)
|
| 2841 |
assert controls_after_execute["autoplay"] is True
|
| 2842 |
assert controls_after_execute["paused"] is False
|
|
|
|
| 2930 |
"execDisabled": False,
|
| 2931 |
"refDisabled": False,
|
| 2932 |
}
|
| 2933 |
+
assert _read_log_output_value(page) == config_module.UI_TEXT["log"]["action_selection_prompt"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2934 |
|
| 2935 |
browser.close()
|
| 2936 |
finally:
|
|
|
|
| 3065 |
value={
|
| 3066 |
"preserve_terminal_log": False,
|
| 3067 |
"terminal_log_value": None,
|
| 3068 |
+
"preserve_execute_video_log": False,
|
| 3069 |
+
"execute_video_log_value": None,
|
| 3070 |
}
|
| 3071 |
)
|
| 3072 |
suppress_state = gr.State(value=False)
|
|
|
|
| 3168 |
log_output,
|
| 3169 |
reference_action_btn,
|
| 3170 |
task_hint_display,
|
| 3171 |
+
post_execute_log_state,
|
| 3172 |
phase_state,
|
| 3173 |
],
|
| 3174 |
queue=False,
|
|
|
|
| 3188 |
log_output,
|
| 3189 |
reference_action_btn,
|
| 3190 |
task_hint_display,
|
| 3191 |
+
post_execute_log_state,
|
| 3192 |
phase_state,
|
| 3193 |
],
|
| 3194 |
queue=False,
|
gradio-web/test/test_ui_text_config.py
CHANGED
|
@@ -103,10 +103,33 @@ def test_on_execute_video_end_transition_restores_controls_for_non_terminal_stat
|
|
| 103 |
assert result[4]["interactive"] is True
|
| 104 |
assert result[5]["interactive"] is True
|
| 105 |
assert result[6]["interactive"] is True
|
| 106 |
-
assert result[8]
|
| 107 |
assert result[9]["interactive"] is True
|
| 108 |
assert result[10]["interactive"] is True
|
| 109 |
-
assert result[11] ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
|
| 112 |
def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_module):
|
|
@@ -134,7 +157,13 @@ def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_
|
|
| 134 |
assert result[8]["value"] == "terminal banner"
|
| 135 |
assert result[9]["interactive"] is False
|
| 136 |
assert result[10]["interactive"] is True
|
| 137 |
-
assert result[11] ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
|
| 140 |
def test_on_option_select_preserves_terminal_log_state(reload_module):
|
|
@@ -158,6 +187,36 @@ def test_on_option_select_preserves_terminal_log_state(reload_module):
|
|
| 158 |
assert log_state == {
|
| 159 |
"preserve_terminal_log": True,
|
| 160 |
"terminal_log_value": "episode success banner",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
}
|
| 162 |
|
| 163 |
|
|
|
|
| 103 |
assert result[4]["interactive"] is True
|
| 104 |
assert result[5]["interactive"] is True
|
| 105 |
assert result[6]["interactive"] is True
|
| 106 |
+
assert result[8]["value"] == callbacks.UI_TEXT["log"]["action_selection_prompt"]
|
| 107 |
assert result[9]["interactive"] is True
|
| 108 |
assert result[10]["interactive"] is True
|
| 109 |
+
assert result[11] == callbacks._default_post_execute_log_state()
|
| 110 |
+
assert result[12] == "action_point"
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def test_on_execute_video_end_transition_clears_execution_video_log_state(reload_module):
|
| 114 |
+
callbacks = reload_module("gradio_callbacks")
|
| 115 |
+
|
| 116 |
+
result = callbacks.on_execute_video_end_transition(
|
| 117 |
+
"uid-1",
|
| 118 |
+
{
|
| 119 |
+
"exec_btn_interactive": True,
|
| 120 |
+
"reference_action_interactive": True,
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"preserve_terminal_log": False,
|
| 124 |
+
"terminal_log_value": None,
|
| 125 |
+
"preserve_execute_video_log": True,
|
| 126 |
+
"execute_video_log_value": "Executing Action b",
|
| 127 |
+
},
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
assert result[8]["value"] == callbacks.UI_TEXT["log"]["action_selection_prompt"]
|
| 131 |
+
assert result[11] == callbacks._default_post_execute_log_state()
|
| 132 |
+
assert result[12] == "action_point"
|
| 133 |
|
| 134 |
|
| 135 |
def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_module):
|
|
|
|
| 157 |
assert result[8]["value"] == "terminal banner"
|
| 158 |
assert result[9]["interactive"] is False
|
| 159 |
assert result[10]["interactive"] is True
|
| 160 |
+
assert result[11] == callbacks._normalize_post_execute_log_state(
|
| 161 |
+
{
|
| 162 |
+
"preserve_terminal_log": True,
|
| 163 |
+
"terminal_log_value": "terminal banner",
|
| 164 |
+
}
|
| 165 |
+
)
|
| 166 |
+
assert result[12] == "action_point"
|
| 167 |
|
| 168 |
|
| 169 |
def test_on_option_select_preserves_terminal_log_state(reload_module):
|
|
|
|
| 187 |
assert log_state == {
|
| 188 |
"preserve_terminal_log": True,
|
| 189 |
"terminal_log_value": "episode success banner",
|
| 190 |
+
"preserve_execute_video_log": False,
|
| 191 |
+
"execute_video_log_value": None,
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def test_on_option_select_preserves_execution_video_log_state(reload_module):
|
| 196 |
+
callbacks = reload_module("gradio_callbacks")
|
| 197 |
+
|
| 198 |
+
coords_update, img_update, log_update, suppress_flag, log_state = callbacks.on_option_select(
|
| 199 |
+
"uid-1",
|
| 200 |
+
1,
|
| 201 |
+
callbacks.UI_TEXT["coords"]["select_point"],
|
| 202 |
+
False,
|
| 203 |
+
{
|
| 204 |
+
"preserve_terminal_log": False,
|
| 205 |
+
"terminal_log_value": None,
|
| 206 |
+
"preserve_execute_video_log": True,
|
| 207 |
+
"execute_video_log_value": "Executing Action b",
|
| 208 |
+
},
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
assert coords_update.get("__type__") == "update"
|
| 212 |
+
assert img_update.get("__type__") == "update"
|
| 213 |
+
assert log_update["value"] == "Executing Action b"
|
| 214 |
+
assert suppress_flag is False
|
| 215 |
+
assert log_state == {
|
| 216 |
+
"preserve_terminal_log": False,
|
| 217 |
+
"terminal_log_value": None,
|
| 218 |
+
"preserve_execute_video_log": True,
|
| 219 |
+
"execute_video_log_value": "Executing Action b",
|
| 220 |
}
|
| 221 |
|
| 222 |
|
gradio-web/ui_layout.py
CHANGED
|
@@ -969,6 +969,8 @@ def create_ui_blocks():
|
|
| 969 |
value={
|
| 970 |
"preserve_terminal_log": False,
|
| 971 |
"terminal_log_value": None,
|
|
|
|
|
|
|
| 972 |
}
|
| 973 |
)
|
| 974 |
current_task_env_state = gr.State(value=None)
|
|
@@ -1425,6 +1427,7 @@ def create_ui_blocks():
|
|
| 1425 |
log_output,
|
| 1426 |
reference_action_btn,
|
| 1427 |
task_hint_display,
|
|
|
|
| 1428 |
ui_phase_state,
|
| 1429 |
],
|
| 1430 |
queue=False,
|
|
@@ -1451,6 +1454,7 @@ def create_ui_blocks():
|
|
| 1451 |
log_output,
|
| 1452 |
reference_action_btn,
|
| 1453 |
task_hint_display,
|
|
|
|
| 1454 |
ui_phase_state,
|
| 1455 |
],
|
| 1456 |
queue=False,
|
|
|
|
| 969 |
value={
|
| 970 |
"preserve_terminal_log": False,
|
| 971 |
"terminal_log_value": None,
|
| 972 |
+
"preserve_execute_video_log": False,
|
| 973 |
+
"execute_video_log_value": None,
|
| 974 |
}
|
| 975 |
)
|
| 976 |
current_task_env_state = gr.State(value=None)
|
|
|
|
| 1427 |
log_output,
|
| 1428 |
reference_action_btn,
|
| 1429 |
task_hint_display,
|
| 1430 |
+
post_execute_log_state,
|
| 1431 |
ui_phase_state,
|
| 1432 |
],
|
| 1433 |
queue=False,
|
|
|
|
| 1454 |
log_output,
|
| 1455 |
reference_action_btn,
|
| 1456 |
task_hint_display,
|
| 1457 |
+
post_execute_log_state,
|
| 1458 |
ui_phase_state,
|
| 1459 |
],
|
| 1460 |
queue=False,
|