HongzeFu commited on
Commit
41fc019
·
1 Parent(s): 4ac0c53

gradio遮罩修复1

Browse files
gradio-web/test/test_queue_session_limit_e2e.py CHANGED
@@ -268,6 +268,7 @@ def test_entry_rejects_immediately_when_session_limit_is_full(monkeypatch):
268
  assert overlay_snapshot["width"] and overlay_snapshot["width"] > 0
269
  assert overlay_snapshot["height"] and overlay_snapshot["height"] >= 400
270
  assert overlay_snapshot["background"] == "rgba(255, 255, 255, 0.92)"
 
271
  rejection_snapshot = _read_session_wait_overlay_snapshot(pages[-1])
272
  assert rejection_snapshot["content"] == config.UI_TEXT["progress"]["entry_rejected"]
273
  assert _read_unified_overlay_text(pages[-1]) == config.UI_TEXT["progress"]["entry_rejected"]
@@ -372,6 +373,10 @@ def test_single_load_uses_native_episode_loading_copy(monkeypatch):
372
  assert overlay_snapshot["width"] and overlay_snapshot["width"] > 0
373
  assert overlay_snapshot["height"] and overlay_snapshot["height"] >= 400
374
  assert overlay_snapshot["background"] == "rgba(255, 255, 255, 0.92)"
 
 
 
 
375
 
376
  page.wait_for_selector("#main_interface_root", state="visible", timeout=15000)
377
 
@@ -448,6 +453,7 @@ def test_execute_does_not_use_episode_loading_copy(monkeypatch):
448
  body_text = page.evaluate("() => document.body.innerText")
449
  assert "The episode is loading..." not in body_text
450
  assert "too many people playing" not in body_text
 
451
 
452
  browser.close()
453
  finally:
 
268
  assert overlay_snapshot["width"] and overlay_snapshot["width"] > 0
269
  assert overlay_snapshot["height"] and overlay_snapshot["height"] >= 400
270
  assert overlay_snapshot["background"] == "rgba(255, 255, 255, 0.92)"
271
+ assert pages[-1].evaluate("() => document.getElementById('robomme_episode_loading_copy') === null") is True
272
  rejection_snapshot = _read_session_wait_overlay_snapshot(pages[-1])
273
  assert rejection_snapshot["content"] == config.UI_TEXT["progress"]["entry_rejected"]
274
  assert _read_unified_overlay_text(pages[-1]) == config.UI_TEXT["progress"]["entry_rejected"]
 
373
  assert overlay_snapshot["width"] and overlay_snapshot["width"] > 0
374
  assert overlay_snapshot["height"] and overlay_snapshot["height"] >= 400
375
  assert overlay_snapshot["background"] == "rgba(255, 255, 255, 0.92)"
376
+ assert _read_progress_text(page) == config.UI_TEXT["progress"]["episode_loading"]
377
+ assert page.evaluate("() => document.getElementById('robomme_episode_loading_copy') === null") is True
378
+ wait_snapshot = _read_session_wait_overlay_snapshot(page)
379
+ assert wait_snapshot["content"] is None
380
 
381
  page.wait_for_selector("#main_interface_root", state="visible", timeout=15000)
382
 
 
453
  body_text = page.evaluate("() => document.body.innerText")
454
  assert "The episode is loading..." not in body_text
455
  assert "too many people playing" not in body_text
456
+ assert page.evaluate("() => document.getElementById('robomme_episode_loading_copy') === null") is True
457
 
458
  browser.close()
459
  finally:
gradio-web/test/test_ui_phase_machine_runtime_e2e.py CHANGED
@@ -129,6 +129,72 @@ def _read_log_output_value(page) -> str | None:
129
  )
130
 
131
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  def _read_elem_classes(page, elem_id: str) -> list[str] | None:
133
  return page.evaluate(
134
  """(elemId) => {
@@ -1096,19 +1162,33 @@ def test_unified_loading_overlay_init_flow(monkeypatch):
1096
  page.wait_for_function(
1097
  """() => {
1098
  const node = document.querySelector('.progress-text');
1099
- return !!node && (node.textContent || '').includes('The episode is loading...');
1100
- }"""
1101
- ,
 
 
 
 
 
 
 
 
 
1102
  timeout=5000,
1103
  )
1104
- progress_text = page.evaluate(
1105
- """() => {
1106
- const node = document.querySelector('.progress-text');
1107
- return node ? (node.textContent || '') : '';
1108
- }"""
1109
- )
1110
- assert canonical_copy in progress_text
1111
- assert superseded_copy not in progress_text
 
 
 
 
 
1112
  assert legacy_copy not in page.content()
1113
  assert page.locator("#loading_overlay_group").count() == 0
1114
 
@@ -1139,6 +1219,141 @@ def test_unified_loading_overlay_init_flow(monkeypatch):
1139
  assert calls["init"] >= 1
1140
 
1141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142
  def test_no_video_task_hides_manual_demo_button(monkeypatch):
1143
  ui_layout = importlib.reload(importlib.import_module("ui_layout"))
1144
 
 
129
  )
130
 
131
 
132
+ def _read_progress_markdown_snapshot(page) -> dict[str, bool | str | None]:
133
+ return page.evaluate(
134
+ """() => {
135
+ const host = document.getElementById('native_progress_host');
136
+ const pending = host?.querySelector('.pending');
137
+ const markdown = host?.querySelector('[data-testid="markdown"]');
138
+ const prose = markdown ? markdown.querySelector('.prose, .md') || markdown : null;
139
+ if (!host) {
140
+ return {
141
+ pendingPresent: false,
142
+ pendingVisible: false,
143
+ markdownVisible: false,
144
+ text: null,
145
+ };
146
+ }
147
+ const pendingStyle = pending ? getComputedStyle(pending) : null;
148
+ const markdownStyle = markdown ? getComputedStyle(markdown) : null;
149
+ const text = prose ? ((prose.textContent || '').trim()) : '';
150
+ return {
151
+ pendingPresent: !!pending,
152
+ pendingVisible: !!pendingStyle && pendingStyle.display !== 'none' && pendingStyle.visibility !== 'hidden',
153
+ markdownVisible:
154
+ !!markdownStyle &&
155
+ markdownStyle.display !== 'none' &&
156
+ markdownStyle.visibility !== 'hidden',
157
+ text: text || null,
158
+ };
159
+ }"""
160
+ )
161
+
162
+
163
+ def _read_progress_text_snapshot(page) -> dict[str, float | bool | str | None]:
164
+ return page.evaluate(
165
+ """() => {
166
+ const node = document.querySelector('.progress-text');
167
+ if (!node) {
168
+ return {
169
+ present: false,
170
+ visible: false,
171
+ text: null,
172
+ x: null,
173
+ y: null,
174
+ width: null,
175
+ height: null,
176
+ };
177
+ }
178
+ const style = getComputedStyle(node);
179
+ const rect = node.getBoundingClientRect();
180
+ return {
181
+ present: true,
182
+ visible:
183
+ style.display !== 'none' &&
184
+ style.visibility !== 'hidden' &&
185
+ Number.parseFloat(style.opacity || '1') > 0 &&
186
+ rect.width > 0 &&
187
+ rect.height > 0,
188
+ text: (node.textContent || '').trim() || null,
189
+ x: rect.x,
190
+ y: rect.y,
191
+ width: rect.width,
192
+ height: rect.height,
193
+ };
194
+ }"""
195
+ )
196
+
197
+
198
  def _read_elem_classes(page, elem_id: str) -> list[str] | None:
199
  return page.evaluate(
200
  """(elemId) => {
 
1162
  page.wait_for_function(
1163
  """() => {
1164
  const node = document.querySelector('.progress-text');
1165
+ if (!node) return false;
1166
+ const style = getComputedStyle(node);
1167
+ const rect = node.getBoundingClientRect();
1168
+ return (
1169
+ style.display !== 'none' &&
1170
+ style.visibility !== 'hidden' &&
1171
+ Number.parseFloat(style.opacity || '1') > 0 &&
1172
+ rect.width > 0 &&
1173
+ rect.height > 0 &&
1174
+ (node.textContent || '').includes('The episode is loading...')
1175
+ );
1176
+ }""",
1177
  timeout=5000,
1178
  )
1179
+ progress_snapshot = _read_progress_text_snapshot(page)
1180
+ markdown_snapshot = _read_progress_markdown_snapshot(page)
1181
+
1182
+ assert progress_snapshot["present"] is True
1183
+ assert progress_snapshot["visible"] is True
1184
+ assert progress_snapshot["text"] == canonical_copy
1185
+ assert progress_snapshot["x"] is not None and progress_snapshot["x"] < 500
1186
+ assert progress_snapshot["y"] is not None and progress_snapshot["y"] > 300
1187
+ assert markdown_snapshot["text"] is None
1188
+ assert markdown_snapshot["pendingVisible"] is False
1189
+ assert markdown_snapshot["markdownVisible"] is False
1190
+ assert page.locator("#robomme_episode_loading_copy").count() == 0
1191
+ assert superseded_copy not in str(progress_snapshot["text"] or "")
1192
  assert legacy_copy not in page.content()
1193
  assert page.locator("#loading_overlay_group").count() == 0
1194
 
 
1219
  assert calls["init"] >= 1
1220
 
1221
 
1222
+ def test_episode_loading_copy_after_change_episode(monkeypatch):
1223
+ ui_layout = importlib.reload(importlib.import_module("ui_layout"))
1224
+
1225
+ fake_obs = np.zeros((24, 24, 3), dtype=np.uint8)
1226
+ fake_obs_img = Image.fromarray(fake_obs)
1227
+ calls = {"init": 0, "next": 0}
1228
+
1229
+ def _load_result(uid: str, episode_idx: int, log_text: str):
1230
+ return (
1231
+ uid,
1232
+ gr.update(visible=True), # main_interface
1233
+ gr.update(value=fake_obs_img.copy(), interactive=False), # img_display
1234
+ log_text, # log_output
1235
+ gr.update(choices=[("pick", 0)], value=None), # options_radio
1236
+ "goal", # goal_box
1237
+ "No need for coordinates", # coords_box
1238
+ gr.update(value=None, visible=False), # video_display
1239
+ gr.update(visible=False, interactive=False), # watch_demo_video_btn
1240
+ f"PickXtimes (Episode {episode_idx})", # task_info_box
1241
+ f"Completed: {episode_idx - 1}", # progress_info_box
1242
+ gr.update(interactive=True), # restart_episode_btn
1243
+ gr.update(interactive=True), # next_task_btn
1244
+ gr.update(interactive=True), # exec_btn
1245
+ gr.update(visible=False), # video_phase_group
1246
+ gr.update(visible=True), # action_phase_group
1247
+ gr.update(visible=True), # control_panel_group
1248
+ gr.update(value="hint"), # task_hint_display
1249
+ gr.update(interactive=True), # reference_action_btn
1250
+ )
1251
+
1252
+ def fake_init_app(_request=None):
1253
+ calls["init"] += 1
1254
+ return _load_result("uid-next-episode", 1, "ready-1")
1255
+
1256
+ def fake_load_next_task_wrapper(uid):
1257
+ calls["next"] += 1
1258
+ time.sleep(0.8)
1259
+ return _load_result(uid, 2, "ready-2")
1260
+
1261
+ monkeypatch.setattr(ui_layout, "init_app", fake_init_app)
1262
+ monkeypatch.setattr(ui_layout, "load_next_task_wrapper", fake_load_next_task_wrapper)
1263
+
1264
+ demo = ui_layout.create_ui_blocks()
1265
+
1266
+ port = _free_port()
1267
+ host = "127.0.0.1"
1268
+ root_url = f"http://{host}:{port}/"
1269
+
1270
+ app = FastAPI(title="episode-loading-copy-change-episode-test")
1271
+ app = gr.mount_gradio_app(app, demo, path="/")
1272
+
1273
+ config = uvicorn.Config(app, host=host, port=port, log_level="error")
1274
+ server = uvicorn.Server(config)
1275
+ thread = threading.Thread(target=server.run, daemon=True)
1276
+ thread.start()
1277
+ _wait_http_ready(root_url)
1278
+
1279
+ try:
1280
+ with sync_playwright() as p:
1281
+ browser = p.chromium.launch(headless=True)
1282
+ page = browser.new_page(viewport={"width": 1280, "height": 900})
1283
+ page.goto(root_url, wait_until="domcontentloaded")
1284
+ page.wait_for_selector("#main_interface_root", state="visible", timeout=15000)
1285
+ page.wait_for_function(
1286
+ """() => {
1287
+ const root = document.getElementById('header_task');
1288
+ if (!root) return false;
1289
+ const input = root.querySelector('input');
1290
+ if (input && typeof input.value === 'string' && input.value.trim() === 'PickXtimes') {
1291
+ return true;
1292
+ }
1293
+ const selected = root.querySelector('.single-select');
1294
+ return !!selected && (selected.textContent || '').trim() === 'PickXtimes';
1295
+ }""",
1296
+ timeout=5000,
1297
+ )
1298
+ page.wait_for_function(
1299
+ """() => {
1300
+ const host = document.getElementById('native_progress_host');
1301
+ const markdown = host?.querySelector('[data-testid="markdown"]');
1302
+ const prose = markdown ? markdown.querySelector('.prose, .md') || markdown : null;
1303
+ const text = prose ? ((prose.innerText || prose.textContent || '').trim()) : '';
1304
+ return text === '';
1305
+ }""",
1306
+ timeout=5000,
1307
+ )
1308
+
1309
+ page.locator("#next_task_btn button, button#next_task_btn").first.click()
1310
+
1311
+ page.wait_for_function(
1312
+ """() => {
1313
+ const node = document.querySelector('.progress-text');
1314
+ if (!node) return false;
1315
+ const style = getComputedStyle(node);
1316
+ const rect = node.getBoundingClientRect();
1317
+ return (
1318
+ style.display !== 'none' &&
1319
+ style.visibility !== 'hidden' &&
1320
+ Number.parseFloat(style.opacity || '1') > 0 &&
1321
+ rect.width > 0 &&
1322
+ rect.height > 0 &&
1323
+ (node.textContent || '').trim() === 'The episode is loading...'
1324
+ );
1325
+ }""",
1326
+ timeout=5000,
1327
+ )
1328
+
1329
+ progress_snapshot = _read_progress_text_snapshot(page)
1330
+ markdown_snapshot = _read_progress_markdown_snapshot(page)
1331
+ assert progress_snapshot["present"] is True
1332
+ assert progress_snapshot["visible"] is True
1333
+ assert progress_snapshot["text"] == "The episode is loading..."
1334
+ assert markdown_snapshot["text"] is None
1335
+ assert markdown_snapshot["pendingVisible"] is False
1336
+ assert markdown_snapshot["markdownVisible"] is False
1337
+ assert page.locator("#robomme_episode_loading_copy").count() == 0
1338
+
1339
+ deadline = time.time() + 15.0
1340
+ while time.time() < deadline:
1341
+ if _read_log_output_value(page) == "ready-2":
1342
+ break
1343
+ time.sleep(0.1)
1344
+ else:
1345
+ raise AssertionError("next episode load did not complete")
1346
+ assert page.locator("#robomme_episode_loading_copy").count() == 0
1347
+
1348
+ browser.close()
1349
+ finally:
1350
+ server.should_exit = True
1351
+ thread.join(timeout=10)
1352
+ demo.close()
1353
+
1354
+ assert calls == {"init": 1, "next": 1}
1355
+
1356
+
1357
  def test_no_video_task_hides_manual_demo_button(monkeypatch):
1358
  ui_layout = importlib.reload(importlib.import_module("ui_layout"))
1359
 
gradio-web/ui_layout.py CHANGED
@@ -367,17 +367,54 @@ PROGRESS_TEXT_REWRITE_JS = f"""
367
  () => {{
368
  const modeEpisodeLoad = {json.dumps(LOAD_STATUS_MODE_EPISODE_LOAD)};
369
  const modeIdle = {json.dumps(LOAD_STATUS_MODE_IDLE)};
 
 
 
370
  const episodeLoadingText = {json.dumps(UI_TEXT["progress"]["episode_loading"])};
371
  const queueWaitText = {json.dumps(UI_TEXT["progress"]["queue_wait"])};
372
  const elapsedOnlyPattern = /^\\d+(?:\\.\\d+)?s$/i;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
 
374
  window.__robommeLoadStatusMode = window.__robommeLoadStatusMode || modeIdle;
375
  const getMode = () => window.__robommeLoadStatusMode || modeIdle;
376
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  const ensureOverlayStyles = () => {{
378
  const host = document.getElementById("native_progress_host");
379
  if (!(host instanceof HTMLElement)) {{
380
- return;
381
  }}
382
  host.style.setProperty("position", "fixed", "important");
383
  host.style.setProperty("inset", "0", "important");
@@ -407,6 +444,12 @@ PROGRESS_TEXT_REWRITE_JS = f"""
407
  markdown instanceof HTMLElement
408
  ? markdown.querySelector(".prose, .md") || markdown
409
  : null;
 
 
 
 
 
 
410
  if (markdown instanceof HTMLElement) {{
411
  markdown.style.setProperty("position", "fixed", "important");
412
  markdown.style.setProperty("inset", "0", "important");
@@ -427,72 +470,165 @@ PROGRESS_TEXT_REWRITE_JS = f"""
427
  prose.style.setProperty("line-height", "1.5", "important");
428
  prose.style.setProperty("white-space", "pre-line", "important");
429
  }}
 
 
 
 
 
 
 
430
  }};
431
 
432
- const splitSegments = (text) =>
433
- text
434
- .split("|")
435
- .map((part) => part.trim())
436
- .filter(Boolean);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
 
438
- const rewriteNode = (node) => {{
 
439
  if (!(node instanceof HTMLElement)) {{
440
  return;
441
  }}
442
 
443
- const displayed = (node.innerText || node.textContent || "").trim();
444
- const previousCustom = node.dataset.robommeProgressCustom || "";
445
- const raw =
446
- node.dataset.robommeProgressCustomized === "1" && displayed === previousCustom
447
- ? node.dataset.robommeProgressRaw || displayed
448
- : displayed;
449
  if (getMode() !== modeEpisodeLoad) {{
450
- if (
451
- (elapsedOnlyPattern.test(raw) ||
452
- /^processing/i.test(raw) ||
453
- /^queue:/i.test(raw))
454
- ) {{
455
  node.textContent = "";
456
  }}
457
- if (
458
- node.dataset.robommeProgressCustomized === "1" &&
459
- displayed === previousCustom &&
460
- node.dataset.robommeProgressRaw
461
- ) {{
462
- node.textContent = node.dataset.robommeProgressRaw;
463
- }}
464
- delete node.dataset.robommeProgressCustomized;
465
- delete node.dataset.robommeProgressRaw;
466
- delete node.dataset.robommeProgressCustom;
467
  return;
468
  }}
469
 
470
- const normalized = raw.toLowerCase();
471
- let custom = null;
472
-
473
- if (normalized.startsWith("processing")) {{
474
- const segments = splitSegments(raw);
475
- const suffix = segments.length > 1 ? ` | ${{segments.slice(1).join(" | ")}}` : "";
476
- custom = `${{episodeLoadingText}}${{suffix}}`;
477
- }} else if (normalized.startsWith("queue:")) {{
478
- custom = `${{queueWaitText}} | ${{raw}}`;
479
  }}
480
 
481
- if (!custom) {{
 
 
 
 
 
 
 
482
  return;
483
  }}
484
 
485
- node.dataset.robommeProgressCustomized = "1";
486
- node.dataset.robommeProgressRaw = raw;
487
- node.dataset.robommeProgressCustom = custom;
488
- if (displayed !== custom) {{
489
- node.textContent = custom;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  }}
491
  }};
492
 
493
  const rewriteAll = () => {{
494
- ensureOverlayStyles();
495
- document.querySelectorAll(".progress-text").forEach(rewriteNode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  }};
497
 
498
  const scheduleRewrite = () => {{
@@ -799,7 +935,7 @@ def create_ui_blocks():
799
 
800
  with gr.Column(visible=True, elem_id="main_interface_root") as main_interface:
801
  native_progress_host = gr.Markdown(
802
- value=UI_TEXT["progress"]["episode_loading"],
803
  visible=True,
804
  container=False,
805
  elem_id="native_progress_host",
 
367
  () => {{
368
  const modeEpisodeLoad = {json.dumps(LOAD_STATUS_MODE_EPISODE_LOAD)};
369
  const modeIdle = {json.dumps(LOAD_STATUS_MODE_IDLE)};
370
+ const overlayStateIdle = "idle";
371
+ const overlayStateEpisodeLoad = "episode-load";
372
+ const overlayStateQueue = "queue";
373
  const episodeLoadingText = {json.dumps(UI_TEXT["progress"]["episode_loading"])};
374
  const queueWaitText = {json.dumps(UI_TEXT["progress"]["queue_wait"])};
375
  const elapsedOnlyPattern = /^\\d+(?:\\.\\d+)?s$/i;
376
+ const progressStyleKeys = [
377
+ "position",
378
+ "top",
379
+ "right",
380
+ "bottom",
381
+ "left",
382
+ "transform",
383
+ "width",
384
+ "max-width",
385
+ "display",
386
+ "margin",
387
+ "text-align",
388
+ "color",
389
+ "font-size",
390
+ "font-weight",
391
+ "line-height",
392
+ "white-space",
393
+ "z-index",
394
+ "order",
395
+ ];
396
+ const wrapStyleKeys = ["flex-direction", "gap"];
397
+ const spinnerStyleKeys = ["order"];
398
 
399
  window.__robommeLoadStatusMode = window.__robommeLoadStatusMode || modeIdle;
400
  const getMode = () => window.__robommeLoadStatusMode || modeIdle;
401
 
402
+ const isEpisodeLoadRaw = (raw) =>
403
+ elapsedOnlyPattern.test(raw) || /^processing/i.test(raw);
404
+
405
+ const isQueueRaw = (raw) => /^queue:/i.test(raw);
406
+
407
+ const clearInlineStyles = (node, keys) => {{
408
+ if (!(node instanceof HTMLElement)) {{
409
+ return;
410
+ }}
411
+ keys.forEach((key) => node.style.removeProperty(key));
412
+ }};
413
+
414
  const ensureOverlayStyles = () => {{
415
  const host = document.getElementById("native_progress_host");
416
  if (!(host instanceof HTMLElement)) {{
417
+ return null;
418
  }}
419
  host.style.setProperty("position", "fixed", "important");
420
  host.style.setProperty("inset", "0", "important");
 
444
  markdown instanceof HTMLElement
445
  ? markdown.querySelector(".prose, .md") || markdown
446
  : null;
447
+ const pending =
448
+ markdown instanceof HTMLElement ? markdown.closest(".pending") : host.querySelector(".pending");
449
+ const spinner =
450
+ host.querySelector("svg") instanceof SVGElement
451
+ ? host.querySelector("svg").closest("div")
452
+ : null;
453
  if (markdown instanceof HTMLElement) {{
454
  markdown.style.setProperty("position", "fixed", "important");
455
  markdown.style.setProperty("inset", "0", "important");
 
470
  prose.style.setProperty("line-height", "1.5", "important");
471
  prose.style.setProperty("white-space", "pre-line", "important");
472
  }}
473
+ return {{
474
+ wrap,
475
+ markdown,
476
+ prose,
477
+ pending,
478
+ spinner,
479
+ }};
480
  }};
481
 
482
+ const resolveRawText = (node) => {{
483
+ const displayed = (node.innerText || node.textContent || "").trim();
484
+ return node.dataset.robommeProgressRaw || displayed;
485
+ }};
486
+
487
+ const setProgressNodeVisible = (node, visible) => {{
488
+ node.style.setProperty("visibility", visible ? "visible" : "hidden", "important");
489
+ node.style.setProperty("opacity", visible ? "1" : "0", "important");
490
+ }};
491
+
492
+ const resetProgressNode = (node) => {{
493
+ const raw = node.dataset.robommeProgressRaw || (node.innerText || node.textContent || "").trim();
494
+ if (raw) {{
495
+ node.textContent = raw;
496
+ }}
497
+ delete node.dataset.robommeProgressCustomized;
498
+ delete node.dataset.robommeProgressRaw;
499
+ delete node.dataset.robommeProgressCustom;
500
+ clearInlineStyles(node, progressStyleKeys);
501
+ setProgressNodeVisible(node, true);
502
+ }};
503
+
504
+ const applyEpisodeLoadLayout = (entry, overlayRefs) => {{
505
+ const node = entry.node;
506
+ const {{
507
+ wrap,
508
+ spinner,
509
+ }} = overlayRefs || {{}};
510
+ if (wrap instanceof HTMLElement) {{
511
+ wrap.style.setProperty("flex-direction", "column", "important");
512
+ wrap.style.setProperty("gap", "24px", "important");
513
+ }}
514
+ if (spinner instanceof HTMLElement) {{
515
+ spinner.style.setProperty("order", "1", "important");
516
+ }}
517
+ node.dataset.robommeProgressCustomized = "1";
518
+ node.dataset.robommeProgressCustom = episodeLoadingText;
519
+ node.textContent = episodeLoadingText;
520
+ setProgressNodeVisible(node, true);
521
+ node.style.setProperty("position", "static", "important");
522
+ node.style.setProperty("top", "auto", "important");
523
+ node.style.setProperty("right", "auto", "important");
524
+ node.style.setProperty("bottom", "auto", "important");
525
+ node.style.setProperty("left", "auto", "important");
526
+ node.style.setProperty("transform", "none", "important");
527
+ node.style.setProperty("width", "min(720px, calc(100vw - 48px))", "important");
528
+ node.style.setProperty("max-width", "calc(100vw - 48px)", "important");
529
+ node.style.setProperty("display", "block", "important");
530
+ node.style.setProperty("margin", "0", "important");
531
+ node.style.setProperty("text-align", "center", "important");
532
+ node.style.setProperty("color", "#0f172a", "important");
533
+ node.style.setProperty("font-size", "var(--text-lg)", "important");
534
+ node.style.setProperty("font-weight", "600", "important");
535
+ node.style.setProperty("line-height", "1.5", "important");
536
+ node.style.setProperty("white-space", "pre-line", "important");
537
+ node.style.setProperty("z-index", "20", "important");
538
+ node.style.setProperty("order", "2", "important");
539
+ }};
540
 
541
+ const rewriteNode = (entry, overlayState) => {{
542
+ const node = entry.node;
543
  if (!(node instanceof HTMLElement)) {{
544
  return;
545
  }}
546
 
547
+ const raw = entry.raw;
 
 
 
 
 
548
  if (getMode() !== modeEpisodeLoad) {{
549
+ resetProgressNode(node);
550
+ if (isEpisodeLoadRaw(raw) || isQueueRaw(raw)) {{
 
 
 
551
  node.textContent = "";
552
  }}
 
 
 
 
 
 
 
 
 
 
553
  return;
554
  }}
555
 
556
+ node.dataset.robommeProgressRaw = raw;
557
+ if (overlayState === overlayStateEpisodeLoad && isEpisodeLoadRaw(raw)) {{
558
+ applyEpisodeLoadLayout(entry, window.__robommeOverlayRefs || null);
559
+ return;
 
 
 
 
 
560
  }}
561
 
562
+ if (overlayState === overlayStateQueue && isQueueRaw(raw)) {{
563
+ const custom = `${{queueWaitText}} | ${{raw}}`;
564
+ node.dataset.robommeProgressCustomized = "1";
565
+ node.dataset.robommeProgressCustom = custom;
566
+ if ((node.innerText || node.textContent || "").trim() !== custom) {{
567
+ node.textContent = custom;
568
+ }}
569
+ setProgressNodeVisible(node, true);
570
  return;
571
  }}
572
 
573
+ resetProgressNode(node);
574
+ }};
575
+
576
+ const syncOverlayContent = (overlayRefs, overlayState) => {{
577
+ if (!overlayRefs) {{
578
+ return;
579
+ }}
580
+ const {{
581
+ wrap,
582
+ markdown,
583
+ prose,
584
+ pending,
585
+ spinner,
586
+ }} = overlayRefs;
587
+ const markdownText =
588
+ prose instanceof HTMLElement ? ((prose.innerText || prose.textContent || "").trim()) : "";
589
+ const showMarkdown = overlayState === overlayStateIdle && markdownText.length > 0;
590
+
591
+ if (wrap instanceof HTMLElement && overlayState !== overlayStateEpisodeLoad) {{
592
+ clearInlineStyles(wrap, wrapStyleKeys);
593
+ }}
594
+ if (spinner instanceof HTMLElement && overlayState !== overlayStateEpisodeLoad) {{
595
+ clearInlineStyles(spinner, spinnerStyleKeys);
596
+ }}
597
+ if (pending instanceof HTMLElement) {{
598
+ pending.style.setProperty("display", showMarkdown ? "block" : "none", "important");
599
+ pending.style.setProperty("visibility", showMarkdown ? "visible" : "hidden", "important");
600
+ }}
601
+ if (markdown instanceof HTMLElement) {{
602
+ markdown.style.setProperty("display", showMarkdown ? "flex" : "none", "important");
603
+ markdown.style.setProperty("visibility", showMarkdown ? "visible" : "hidden", "important");
604
  }}
605
  }};
606
 
607
  const rewriteAll = () => {{
608
+ const overlayRefs = ensureOverlayStyles();
609
+ window.__robommeOverlayRefs = overlayRefs;
610
+ const progressEntries = Array.from(document.querySelectorAll(".progress-text"))
611
+ .filter((node) => node instanceof HTMLElement)
612
+ .map((node) => {{
613
+ const raw = resolveRawText(node);
614
+ return {{
615
+ node,
616
+ raw,
617
+ }};
618
+ }});
619
+ let overlayState = overlayStateIdle;
620
+ if (getMode() === modeEpisodeLoad) {{
621
+ const hasEpisodeLoad = progressEntries.some((entry) => isEpisodeLoadRaw(entry.raw));
622
+ const hasQueue = progressEntries.some((entry) => isQueueRaw(entry.raw));
623
+ if (hasEpisodeLoad) {{
624
+ overlayState = overlayStateEpisodeLoad;
625
+ }} else if (hasQueue) {{
626
+ overlayState = overlayStateQueue;
627
+ }}
628
+ }}
629
+
630
+ progressEntries.forEach((entry) => rewriteNode(entry, overlayState));
631
+ syncOverlayContent(overlayRefs, overlayState);
632
  }};
633
 
634
  const scheduleRewrite = () => {{
 
935
 
936
  with gr.Column(visible=True, elem_id="main_interface_root") as main_interface:
937
  native_progress_host = gr.Markdown(
938
+ value="",
939
  visible=True,
940
  container=False,
941
  elem_id="native_progress_host",