ground truth action button style update,css update
Browse files
gradio-web/main.py
CHANGED
|
@@ -123,7 +123,7 @@ def build_allowed_paths():
|
|
| 123 |
|
| 124 |
def main():
|
| 125 |
from state_manager import start_timeout_monitor
|
| 126 |
-
from ui_layout import create_ui_blocks
|
| 127 |
|
| 128 |
LOGGER.info("Starting Gradio real environment entrypoint: %s", __file__)
|
| 129 |
log_runtime_graphics_env()
|
|
@@ -150,6 +150,7 @@ def main():
|
|
| 150 |
debug=True,
|
| 151 |
show_error=True,
|
| 152 |
quiet=False,
|
|
|
|
| 153 |
)
|
| 154 |
|
| 155 |
|
|
|
|
| 123 |
|
| 124 |
def main():
|
| 125 |
from state_manager import start_timeout_monitor
|
| 126 |
+
from ui_layout import CSS, create_ui_blocks
|
| 127 |
|
| 128 |
LOGGER.info("Starting Gradio real environment entrypoint: %s", __file__)
|
| 129 |
log_runtime_graphics_env()
|
|
|
|
| 150 |
debug=True,
|
| 151 |
show_error=True,
|
| 152 |
quiet=False,
|
| 153 |
+
css=CSS,
|
| 154 |
)
|
| 155 |
|
| 156 |
|
gradio-web/test/test_main_launch_config.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import sys
|
| 4 |
+
import types
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class _FakeDemo:
|
| 8 |
+
def __init__(self):
|
| 9 |
+
self.launch_kwargs = None
|
| 10 |
+
|
| 11 |
+
def launch(self, **kwargs):
|
| 12 |
+
self.launch_kwargs = kwargs
|
| 13 |
+
return None
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_main_launch_passes_ui_css(monkeypatch, reload_module):
|
| 17 |
+
main = reload_module("main")
|
| 18 |
+
fake_demo = _FakeDemo()
|
| 19 |
+
timeout_calls = {"count": 0}
|
| 20 |
+
|
| 21 |
+
fake_state_manager = types.SimpleNamespace(
|
| 22 |
+
start_timeout_monitor=lambda: timeout_calls.__setitem__("count", timeout_calls["count"] + 1)
|
| 23 |
+
)
|
| 24 |
+
fake_ui_layout = types.SimpleNamespace(
|
| 25 |
+
CSS="#reference_action_btn button:not(:disabled){background:#1f8b4c;}",
|
| 26 |
+
create_ui_blocks=lambda: fake_demo,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
monkeypatch.setitem(sys.modules, "state_manager", fake_state_manager)
|
| 30 |
+
monkeypatch.setitem(sys.modules, "ui_layout", fake_ui_layout)
|
| 31 |
+
monkeypatch.setenv("PORT", "7861")
|
| 32 |
+
|
| 33 |
+
main.main()
|
| 34 |
+
|
| 35 |
+
assert timeout_calls["count"] == 1
|
| 36 |
+
assert fake_demo.launch_kwargs is not None
|
| 37 |
+
assert fake_demo.launch_kwargs["server_name"] == "0.0.0.0"
|
| 38 |
+
assert fake_demo.launch_kwargs["server_port"] == 7861
|
| 39 |
+
assert fake_demo.launch_kwargs["css"] == fake_ui_layout.CSS
|
gradio-web/test/test_ui_phase_machine_runtime_e2e.py
CHANGED
|
@@ -43,6 +43,32 @@ def _wait_http_ready(url: str, timeout_s: float = 20.0) -> None:
|
|
| 43 |
raise RuntimeError(f"Server did not become ready: {url}")
|
| 44 |
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
def _read_header_task_value(page) -> str | None:
|
| 47 |
return page.evaluate(
|
| 48 |
"""() => {
|
|
@@ -102,8 +128,10 @@ def _read_live_obs_geometry(page) -> dict[str, dict[str, float] | None]:
|
|
| 102 |
def phase_machine_ui_url():
|
| 103 |
state = {"precheck_calls": 0}
|
| 104 |
demo_video_url = "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
|
|
|
|
| 105 |
|
| 106 |
with gr.Blocks(title="Native phase machine test") as demo:
|
|
|
|
| 107 |
phase_state = gr.State("init")
|
| 108 |
|
| 109 |
with gr.Column(visible=True, elem_id="login_group") as login_group:
|
|
@@ -121,6 +149,11 @@ def phase_machine_ui_url():
|
|
| 121 |
coords_box = gr.Textbox(value="please click the keypoint selection image", elem_id="coords_box")
|
| 122 |
with gr.Column(visible=False, elem_id="action_buttons_row") as action_buttons_row:
|
| 123 |
exec_btn = gr.Button("EXECUTE", elem_id="exec_btn")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
next_task_btn = gr.Button("Next Task", elem_id="next_task_btn")
|
| 125 |
|
| 126 |
log_output = gr.Markdown("", elem_id="log_output")
|
|
@@ -134,6 +167,7 @@ def phase_machine_ui_url():
|
|
| 134 |
gr.update(visible=False),
|
| 135 |
gr.update(visible=False),
|
| 136 |
gr.update(visible=False),
|
|
|
|
| 137 |
gr.update(value="please click the keypoint selection image"),
|
| 138 |
"demo_video",
|
| 139 |
)
|
|
@@ -144,6 +178,7 @@ def phase_machine_ui_url():
|
|
| 144 |
gr.update(visible=True),
|
| 145 |
gr.update(visible=True),
|
| 146 |
gr.update(visible=True),
|
|
|
|
| 147 |
"action_keypoint",
|
| 148 |
)
|
| 149 |
|
|
@@ -158,6 +193,7 @@ def phase_machine_ui_url():
|
|
| 158 |
gr.update(interactive=False),
|
| 159 |
gr.update(interactive=False),
|
| 160 |
gr.update(interactive=False),
|
|
|
|
| 161 |
"execution_playback",
|
| 162 |
)
|
| 163 |
|
|
@@ -175,6 +211,7 @@ def phase_machine_ui_url():
|
|
| 175 |
gr.update(interactive=True),
|
| 176 |
gr.update(interactive=True),
|
| 177 |
gr.update(interactive=True),
|
|
|
|
| 178 |
"action_keypoint",
|
| 179 |
)
|
| 180 |
|
|
@@ -188,6 +225,7 @@ def phase_machine_ui_url():
|
|
| 188 |
action_phase_group,
|
| 189 |
control_panel_group,
|
| 190 |
action_buttons_row,
|
|
|
|
| 191 |
coords_box,
|
| 192 |
phase_state,
|
| 193 |
],
|
|
@@ -196,7 +234,14 @@ def phase_machine_ui_url():
|
|
| 196 |
|
| 197 |
video_display.end(
|
| 198 |
fn=on_video_end_fn,
|
| 199 |
-
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
queue=False,
|
| 201 |
)
|
| 202 |
|
|
@@ -212,6 +257,7 @@ def phase_machine_ui_url():
|
|
| 212 |
exec_btn,
|
| 213 |
next_task_btn,
|
| 214 |
img_display,
|
|
|
|
| 215 |
phase_state,
|
| 216 |
],
|
| 217 |
queue=False,
|
|
@@ -221,7 +267,7 @@ def phase_machine_ui_url():
|
|
| 221 |
queue=False,
|
| 222 |
).then(
|
| 223 |
fn=to_action_fn,
|
| 224 |
-
outputs=[options_radio, exec_btn, next_task_btn, img_display, phase_state],
|
| 225 |
queue=False,
|
| 226 |
)
|
| 227 |
|
|
@@ -399,6 +445,52 @@ def test_phase_machine_runtime_flow_and_execute_precheck(phase_machine_ui_url):
|
|
| 399 |
assert state["precheck_calls"] >= 2
|
| 400 |
|
| 401 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
def test_unified_loading_overlay_init_flow(monkeypatch):
|
| 403 |
ui_layout = importlib.reload(importlib.import_module("ui_layout"))
|
| 404 |
|
|
|
|
| 43 |
raise RuntimeError(f"Server did not become ready: {url}")
|
| 44 |
|
| 45 |
|
| 46 |
+
def _resolve_button_snapshot(page, elem_id: str) -> dict[str, str | bool | None]:
|
| 47 |
+
return page.evaluate(
|
| 48 |
+
"""(elemId) => {
|
| 49 |
+
const button = document.querySelector(`#${elemId} button`) || document.querySelector(`button#${elemId}`);
|
| 50 |
+
if (!button) {
|
| 51 |
+
return {
|
| 52 |
+
found: false,
|
| 53 |
+
disabled: null,
|
| 54 |
+
backgroundColor: null,
|
| 55 |
+
borderColor: null,
|
| 56 |
+
color: null,
|
| 57 |
+
};
|
| 58 |
+
}
|
| 59 |
+
const style = getComputedStyle(button);
|
| 60 |
+
return {
|
| 61 |
+
found: true,
|
| 62 |
+
disabled: button.disabled,
|
| 63 |
+
backgroundColor: style.backgroundColor,
|
| 64 |
+
borderColor: style.borderColor,
|
| 65 |
+
color: style.color,
|
| 66 |
+
};
|
| 67 |
+
}""",
|
| 68 |
+
elem_id,
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
def _read_header_task_value(page) -> str | None:
|
| 73 |
return page.evaluate(
|
| 74 |
"""() => {
|
|
|
|
| 128 |
def phase_machine_ui_url():
|
| 129 |
state = {"precheck_calls": 0}
|
| 130 |
demo_video_url = "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
|
| 131 |
+
ui_layout = importlib.reload(importlib.import_module("ui_layout"))
|
| 132 |
|
| 133 |
with gr.Blocks(title="Native phase machine test") as demo:
|
| 134 |
+
gr.HTML(f"<style>{ui_layout.CSS}</style>")
|
| 135 |
phase_state = gr.State("init")
|
| 136 |
|
| 137 |
with gr.Column(visible=True, elem_id="login_group") as login_group:
|
|
|
|
| 149 |
coords_box = gr.Textbox(value="please click the keypoint selection image", elem_id="coords_box")
|
| 150 |
with gr.Column(visible=False, elem_id="action_buttons_row") as action_buttons_row:
|
| 151 |
exec_btn = gr.Button("EXECUTE", elem_id="exec_btn")
|
| 152 |
+
reference_action_btn = gr.Button(
|
| 153 |
+
"Ground Truth Action",
|
| 154 |
+
elem_id="reference_action_btn",
|
| 155 |
+
interactive=False,
|
| 156 |
+
)
|
| 157 |
next_task_btn = gr.Button("Next Task", elem_id="next_task_btn")
|
| 158 |
|
| 159 |
log_output = gr.Markdown("", elem_id="log_output")
|
|
|
|
| 167 |
gr.update(visible=False),
|
| 168 |
gr.update(visible=False),
|
| 169 |
gr.update(visible=False),
|
| 170 |
+
gr.update(interactive=False),
|
| 171 |
gr.update(value="please click the keypoint selection image"),
|
| 172 |
"demo_video",
|
| 173 |
)
|
|
|
|
| 178 |
gr.update(visible=True),
|
| 179 |
gr.update(visible=True),
|
| 180 |
gr.update(visible=True),
|
| 181 |
+
gr.update(interactive=True),
|
| 182 |
"action_keypoint",
|
| 183 |
)
|
| 184 |
|
|
|
|
| 193 |
gr.update(interactive=False),
|
| 194 |
gr.update(interactive=False),
|
| 195 |
gr.update(interactive=False),
|
| 196 |
+
gr.update(interactive=False),
|
| 197 |
"execution_playback",
|
| 198 |
)
|
| 199 |
|
|
|
|
| 211 |
gr.update(interactive=True),
|
| 212 |
gr.update(interactive=True),
|
| 213 |
gr.update(interactive=True),
|
| 214 |
+
gr.update(interactive=True),
|
| 215 |
"action_keypoint",
|
| 216 |
)
|
| 217 |
|
|
|
|
| 225 |
action_phase_group,
|
| 226 |
control_panel_group,
|
| 227 |
action_buttons_row,
|
| 228 |
+
reference_action_btn,
|
| 229 |
coords_box,
|
| 230 |
phase_state,
|
| 231 |
],
|
|
|
|
| 234 |
|
| 235 |
video_display.end(
|
| 236 |
fn=on_video_end_fn,
|
| 237 |
+
outputs=[
|
| 238 |
+
video_phase_group,
|
| 239 |
+
action_phase_group,
|
| 240 |
+
control_panel_group,
|
| 241 |
+
action_buttons_row,
|
| 242 |
+
reference_action_btn,
|
| 243 |
+
phase_state,
|
| 244 |
+
],
|
| 245 |
queue=False,
|
| 246 |
)
|
| 247 |
|
|
|
|
| 257 |
exec_btn,
|
| 258 |
next_task_btn,
|
| 259 |
img_display,
|
| 260 |
+
reference_action_btn,
|
| 261 |
phase_state,
|
| 262 |
],
|
| 263 |
queue=False,
|
|
|
|
| 267 |
queue=False,
|
| 268 |
).then(
|
| 269 |
fn=to_action_fn,
|
| 270 |
+
outputs=[options_radio, exec_btn, next_task_btn, img_display, reference_action_btn, phase_state],
|
| 271 |
queue=False,
|
| 272 |
)
|
| 273 |
|
|
|
|
| 445 |
assert state["precheck_calls"] >= 2
|
| 446 |
|
| 447 |
|
| 448 |
+
def test_reference_action_button_is_green_only_when_interactive(phase_machine_ui_url):
|
| 449 |
+
root_url, _state = phase_machine_ui_url
|
| 450 |
+
|
| 451 |
+
with sync_playwright() as p:
|
| 452 |
+
browser = p.chromium.launch(headless=True)
|
| 453 |
+
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
| 454 |
+
page.goto(root_url, wait_until="domcontentloaded")
|
| 455 |
+
|
| 456 |
+
page.wait_for_timeout(2500)
|
| 457 |
+
page.wait_for_selector("#login_btn", timeout=20000)
|
| 458 |
+
page.click("#login_btn")
|
| 459 |
+
|
| 460 |
+
disabled_snapshot = _resolve_button_snapshot(page, "reference_action_btn")
|
| 461 |
+
if disabled_snapshot["found"]:
|
| 462 |
+
assert disabled_snapshot["disabled"] is True
|
| 463 |
+
assert disabled_snapshot["backgroundColor"] != "rgb(31, 139, 76)"
|
| 464 |
+
|
| 465 |
+
page.wait_for_selector("#demo_video video", timeout=5000)
|
| 466 |
+
did_dispatch_end = page.evaluate(
|
| 467 |
+
"""() => {
|
| 468 |
+
const videoEl = document.querySelector('#demo_video video');
|
| 469 |
+
if (!videoEl) return false;
|
| 470 |
+
videoEl.dispatchEvent(new Event('ended', { bubbles: true }));
|
| 471 |
+
return true;
|
| 472 |
+
}"""
|
| 473 |
+
)
|
| 474 |
+
assert did_dispatch_end
|
| 475 |
+
|
| 476 |
+
page.wait_for_function(
|
| 477 |
+
"""() => {
|
| 478 |
+
const button = document.querySelector('#reference_action_btn button') || document.querySelector('button#reference_action_btn');
|
| 479 |
+
return !!button && button.disabled === false;
|
| 480 |
+
}""",
|
| 481 |
+
timeout=6000,
|
| 482 |
+
)
|
| 483 |
+
|
| 484 |
+
enabled_snapshot = _resolve_button_snapshot(page, "reference_action_btn")
|
| 485 |
+
assert enabled_snapshot["found"] is True
|
| 486 |
+
assert enabled_snapshot["disabled"] is False
|
| 487 |
+
assert enabled_snapshot["backgroundColor"] == "rgb(31, 139, 76)"
|
| 488 |
+
assert enabled_snapshot["borderColor"] == "rgb(31, 139, 76)"
|
| 489 |
+
assert enabled_snapshot["color"] == "rgb(255, 255, 255)"
|
| 490 |
+
|
| 491 |
+
browser.close()
|
| 492 |
+
|
| 493 |
+
|
| 494 |
def test_unified_loading_overlay_init_flow(monkeypatch):
|
| 495 |
ui_layout = importlib.reload(importlib.import_module("ui_layout"))
|
| 496 |
|
gradio-web/ui_layout.py
CHANGED
|
@@ -216,17 +216,15 @@ CSS = f"""
|
|
| 216 |
margin: 0 !important;
|
| 217 |
}}
|
| 218 |
|
| 219 |
-
|
| 220 |
-
#reference_action_btn:not(:disabled)
|
| 221 |
-
#reference_action_btn button:not(:disabled) {{
|
| 222 |
background: #1f8b4c !important;
|
| 223 |
border-color: #1f8b4c !important;
|
| 224 |
color: #ffffff !important;
|
| 225 |
}}
|
| 226 |
|
| 227 |
-
|
| 228 |
-
#reference_action_btn:not(:disabled):hover
|
| 229 |
-
#reference_action_btn button:not(:disabled):hover {{
|
| 230 |
background: #19713d !important;
|
| 231 |
border-color: #19713d !important;
|
| 232 |
}}
|
|
|
|
| 216 |
margin: 0 !important;
|
| 217 |
}}
|
| 218 |
|
| 219 |
+
#reference_action_btn button:not(:disabled),
|
| 220 |
+
button#reference_action_btn:not(:disabled) {{
|
|
|
|
| 221 |
background: #1f8b4c !important;
|
| 222 |
border-color: #1f8b4c !important;
|
| 223 |
color: #ffffff !important;
|
| 224 |
}}
|
| 225 |
|
| 226 |
+
#reference_action_btn button:not(:disabled):hover,
|
| 227 |
+
button#reference_action_btn:not(:disabled):hover {{
|
|
|
|
| 228 |
background: #19713d !important;
|
| 229 |
border-color: #19713d !important;
|
| 230 |
}}
|