Spaces:
Running on Zero
fix: Make the demo usable from the page, not just the API.
Browse filesThree things blocked the browser while the endpoint itself was fine:
- gr.Examples cannot hold a File input. Gradio drops the File column from the
examples table, so the row carried five values into six inputs and every
argument after the scene name shifted by one, putting the frame count where
the archive path goes. Dropped the table; the dropdown already selects the
only example scene and the sliders already default to its settings.
- Spaces enable Gradio's server-side rendering through GRADIO_SSR_MODE, and its
node server was answering the page's POSTs with `405 POST method not
allowed`. Rendering client side keeps every request on the Python backend.
- The upload rejected archives client side on extension alone. unpack_scene
checks the magic bytes, which is the stronger test.
Also prune unpacked scenes, not just recordings, so uploads cannot fill the
disk. Verified over HTTP with a real multipart upload: example scene and
uploaded zip both run.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@@ -205,14 +205,18 @@ def unpack_scene(archive_path: str) -> str:
|
|
| 205 |
|
| 206 |
|
| 207 |
def prune_recordings() -> None:
|
| 208 |
-
"""Drop
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
if not os.path.isdir(OUTPUT_ROOT):
|
| 210 |
return
|
| 211 |
|
| 212 |
runs = [
|
| 213 |
entry.path
|
| 214 |
for entry in os.scandir(OUTPUT_ROOT)
|
| 215 |
-
if entry.is_dir() and entry.name.startswith("run-")
|
| 216 |
]
|
| 217 |
|
| 218 |
for path in sorted(runs, key=os.path.getmtime)[:-KEEP_RECORDINGS]:
|
|
@@ -450,10 +454,11 @@ with gr.Blocks(title="Map-Det3D") as demo:
|
|
| 450 |
"Poses have to be metric and share the stem of the frame "
|
| 451 |
"they belong to."
|
| 452 |
)
|
|
|
|
|
|
|
|
|
|
| 453 |
archive = gr.File(
|
| 454 |
-
label="Scene archive (.zip)",
|
| 455 |
-
file_types=[".zip"],
|
| 456 |
-
type="filepath",
|
| 457 |
)
|
| 458 |
|
| 459 |
with gr.Column(scale=3):
|
|
@@ -479,18 +484,20 @@ with gr.Blocks(title="Map-Det3D") as demo:
|
|
| 479 |
]
|
| 480 |
outputs = [viewer, recording_file, status]
|
| 481 |
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
cache_examples=False,
|
| 489 |
-
)
|
| 490 |
-
|
| 491 |
submit_btn.click(fn=run_mapdet3d, inputs=inputs, outputs=outputs)
|
| 492 |
|
| 493 |
if __name__ == "__main__":
|
| 494 |
"""Demo."""
|
| 495 |
os.makedirs(OUTPUT_ROOT, exist_ok=True)
|
| 496 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
|
| 207 |
def prune_recordings() -> None:
|
| 208 |
+
"""Drop older runs and unpacked scenes so the disk does not fill up.
|
| 209 |
+
|
| 210 |
+
Called before a run creates its own directories, so it never removes the
|
| 211 |
+
ones the current request is about to use.
|
| 212 |
+
"""
|
| 213 |
if not os.path.isdir(OUTPUT_ROOT):
|
| 214 |
return
|
| 215 |
|
| 216 |
runs = [
|
| 217 |
entry.path
|
| 218 |
for entry in os.scandir(OUTPUT_ROOT)
|
| 219 |
+
if entry.is_dir() and entry.name.startswith(("run-", "scene-"))
|
| 220 |
]
|
| 221 |
|
| 222 |
for path in sorted(runs, key=os.path.getmtime)[:-KEEP_RECORDINGS]:
|
|
|
|
| 454 |
"Poses have to be metric and share the stem of the frame "
|
| 455 |
"they belong to."
|
| 456 |
)
|
| 457 |
+
# NOTE: No file_types filter. It rejects archives client side
|
| 458 |
+
# by extension alone, and unpack_scene checks the magic bytes
|
| 459 |
+
# anyway, which is the stronger test.
|
| 460 |
archive = gr.File(
|
| 461 |
+
label="Scene archive (.zip)", type="filepath"
|
|
|
|
|
|
|
| 462 |
)
|
| 463 |
|
| 464 |
with gr.Column(scale=3):
|
|
|
|
| 484 |
]
|
| 485 |
outputs = [viewer, recording_file, status]
|
| 486 |
|
| 487 |
+
# NOTE: No gr.Examples here. It cannot hold the upload alongside the other
|
| 488 |
+
# controls: Gradio drops a File column from the examples table, so the row
|
| 489 |
+
# carried five values into six inputs and every argument after the scene
|
| 490 |
+
# name shifted by one, landing the frame count where the archive goes. The
|
| 491 |
+
# dropdown already selects the only example scene and the sliders already
|
| 492 |
+
# default to its settings, so the table added nothing.
|
|
|
|
|
|
|
|
|
|
| 493 |
submit_btn.click(fn=run_mapdet3d, inputs=inputs, outputs=outputs)
|
| 494 |
|
| 495 |
if __name__ == "__main__":
|
| 496 |
"""Demo."""
|
| 497 |
os.makedirs(OUTPUT_ROOT, exist_ok=True)
|
| 498 |
+
|
| 499 |
+
# NOTE: Spaces turn Gradio's server-side rendering on through
|
| 500 |
+
# GRADIO_SSR_MODE, and its node server answers the browser's POSTs with
|
| 501 |
+
# `405 POST method not allowed`, so nothing can be run or uploaded from the
|
| 502 |
+
# page. Rendering client side keeps every request on the Python backend.
|
| 503 |
+
demo.launch(allowed_paths=[OUTPUT_ROOT], ssr_mode=False)
|