Spaces:
Running on Zero
Running on Zero
Fix Invalid URL crash in runPipeline and surface file sizes
Browse filesnew URL(artifactUrl) threw because the artifact URL is a relative path
("/gradio_api/file=..."). Drop the URL parse; instead return the file
size from each @app .api() endpoint alongside the URL, so the UI can
show real byte counts in the Scene tree and Telemetry grid.
app.py
CHANGED
|
@@ -88,7 +88,7 @@ def reconstruct(image_path: FileData) -> dict:
|
|
| 88 |
seconds=round(time.perf_counter() - started, 3),
|
| 89 |
bytes=artifact.stat().st_size,
|
| 90 |
)
|
| 91 |
-
return {"url": _file_url(artifact)}
|
| 92 |
|
| 93 |
|
| 94 |
@app.api(name="export_ply", queue=True, concurrency_limit=2)
|
|
@@ -107,7 +107,7 @@ def export_ply(artifact_url: str) -> dict:
|
|
| 107 |
seconds=round(time.perf_counter() - started, 3),
|
| 108 |
bytes=scene_ply.stat().st_size,
|
| 109 |
)
|
| 110 |
-
return {"url": _file_url(scene_ply)}
|
| 111 |
|
| 112 |
|
| 113 |
@app.api(name="export_viewer", queue=True, concurrency_limit=2)
|
|
@@ -126,7 +126,7 @@ def export_viewer(scene_ply_url: str) -> dict:
|
|
| 126 |
sog_bytes=exported.scene_sog.stat().st_size,
|
| 127 |
viewer_html_bytes=exported.viewer_html.stat().st_size,
|
| 128 |
)
|
| 129 |
-
return {"url": _file_url(exported.viewer_html)}
|
| 130 |
|
| 131 |
|
| 132 |
@app.api(name="export_html", queue=True, concurrency_limit=2)
|
|
@@ -144,7 +144,7 @@ def export_html(viewer_html_url: str) -> dict:
|
|
| 144 |
seconds=round(time.perf_counter() - started, 3),
|
| 145 |
bytes=standalone.stat().st_size,
|
| 146 |
)
|
| 147 |
-
return {"url": _file_url(standalone)}
|
| 148 |
|
| 149 |
|
| 150 |
@app.api(name="viewer_html", queue=False)
|
|
@@ -1293,11 +1293,12 @@ INDEX_HTML = r"""<!doctype html>
|
|
| 1293 |
client.predict("/reconstruct", { image_path: handle_file(pendingFile) })
|
| 1294 |
);
|
| 1295 |
const artifactUrl = reconWrap.result.data[0].url;
|
|
|
|
| 1296 |
stageTimings.gpu = reconWrap.ms;
|
| 1297 |
setStage("reconstruct", "done", fmtSec(reconWrap.ms / 1000));
|
| 1298 |
document.getElementById("telGpu").textContent = fmtSec(reconWrap.ms / 1000);
|
| 1299 |
-
document.getElementById("telArtifact").textContent = fmtBytes(
|
| 1300 |
-
logLine("reconstruct", "ok", `${fmtSec(reconWrap.ms / 1000)} 路
|
| 1301 |
|
| 1302 |
// Stage 2: PLY export
|
| 1303 |
setViewerState("loading", { title: "Preparing PLY", detail: "Filtering Gaussians", progress: 45, stageLabel: "STAGE 2 / 4 路 CPU" });
|
|
@@ -1307,9 +1308,11 @@ INDEX_HTML = r"""<!doctype html>
|
|
| 1307 |
client.predict("/export_ply", { artifact_url: artifactUrl })
|
| 1308 |
);
|
| 1309 |
const plyUrl = plyWrap.result.data[0].url;
|
| 1310 |
-
|
|
|
|
| 1311 |
setDownload(dlPly, plyUrl, "Download PLY");
|
| 1312 |
-
|
|
|
|
| 1313 |
|
| 1314 |
// Stage 3: Viewer
|
| 1315 |
setViewerState("loading", { title: "Encoding viewer", detail: "Building WebGL scene", progress: 70, stageLabel: "STAGE 3 / 4 路 ENCODE" });
|
|
@@ -1319,14 +1322,16 @@ INDEX_HTML = r"""<!doctype html>
|
|
| 1319 |
client.predict("/export_viewer", { scene_ply_url: plyUrl })
|
| 1320 |
);
|
| 1321 |
const viewerUrl = viewWrap.result.data[0].url + "?v=" + Date.now();
|
| 1322 |
-
|
|
|
|
|
|
|
| 1323 |
viewerFrame.src = viewerUrl;
|
| 1324 |
viewerFrame.onload = () => {
|
| 1325 |
viewerFrame.classList.add("ready");
|
| 1326 |
setViewerState("ready");
|
| 1327 |
viewportMeta.textContent = "ready";
|
| 1328 |
};
|
| 1329 |
-
logLine("viewer", "ok", `${fmtSec(viewWrap.ms / 1000)} 路
|
| 1330 |
|
| 1331 |
// Stage 4: HTML
|
| 1332 |
setViewerState("loading", { title: "Bundling HTML", detail: "Embedding assets for download", progress: 92, stageLabel: "STAGE 4 / 4 路 BUNDLE" });
|
|
@@ -1336,12 +1341,13 @@ INDEX_HTML = r"""<!doctype html>
|
|
| 1336 |
client.predict("/export_html", { viewer_html_url: viewerUrl.replace(/[?#].*/, "") })
|
| 1337 |
);
|
| 1338 |
const htmlUrl = htmlWrap.result.data[0].url;
|
| 1339 |
-
|
|
|
|
| 1340 |
setDownload(dlHtml, htmlUrl, "Download HTML");
|
| 1341 |
|
| 1342 |
const totalSec = (performance.now() - pipelineStart) / 1000;
|
| 1343 |
document.getElementById("telTotal").textContent = fmtSec(totalSec);
|
| 1344 |
-
logLine("html", "ok", `${fmtSec(htmlWrap.ms / 1000)} 路
|
| 1345 |
|
| 1346 |
setViewerState("ready");
|
| 1347 |
setStatus("idle", { gpu: "idle", queue: 0, stage: "4 / 4" });
|
|
|
|
| 88 |
seconds=round(time.perf_counter() - started, 3),
|
| 89 |
bytes=artifact.stat().st_size,
|
| 90 |
)
|
| 91 |
+
return {"url": _file_url(artifact), "size": artifact.stat().st_size}
|
| 92 |
|
| 93 |
|
| 94 |
@app.api(name="export_ply", queue=True, concurrency_limit=2)
|
|
|
|
| 107 |
seconds=round(time.perf_counter() - started, 3),
|
| 108 |
bytes=scene_ply.stat().st_size,
|
| 109 |
)
|
| 110 |
+
return {"url": _file_url(scene_ply), "size": scene_ply.stat().st_size}
|
| 111 |
|
| 112 |
|
| 113 |
@app.api(name="export_viewer", queue=True, concurrency_limit=2)
|
|
|
|
| 126 |
sog_bytes=exported.scene_sog.stat().st_size,
|
| 127 |
viewer_html_bytes=exported.viewer_html.stat().st_size,
|
| 128 |
)
|
| 129 |
+
return {"url": _file_url(exported.viewer_html), "size": exported.viewer_html.stat().st_size}
|
| 130 |
|
| 131 |
|
| 132 |
@app.api(name="export_html", queue=True, concurrency_limit=2)
|
|
|
|
| 144 |
seconds=round(time.perf_counter() - started, 3),
|
| 145 |
bytes=standalone.stat().st_size,
|
| 146 |
)
|
| 147 |
+
return {"url": _file_url(standalone), "size": standalone.stat().st_size}
|
| 148 |
|
| 149 |
|
| 150 |
@app.api(name="viewer_html", queue=False)
|
|
|
|
| 1293 |
client.predict("/reconstruct", { image_path: handle_file(pendingFile) })
|
| 1294 |
);
|
| 1295 |
const artifactUrl = reconWrap.result.data[0].url;
|
| 1296 |
+
const artifactSize = reconWrap.result.data[0].size;
|
| 1297 |
stageTimings.gpu = reconWrap.ms;
|
| 1298 |
setStage("reconstruct", "done", fmtSec(reconWrap.ms / 1000));
|
| 1299 |
document.getElementById("telGpu").textContent = fmtSec(reconWrap.ms / 1000);
|
| 1300 |
+
document.getElementById("telArtifact").textContent = fmtBytes(artifactSize);
|
| 1301 |
+
logLine("reconstruct", "ok", `${fmtSec(reconWrap.ms / 1000)} 路 ${fmtBytes(artifactSize)}`);
|
| 1302 |
|
| 1303 |
// Stage 2: PLY export
|
| 1304 |
setViewerState("loading", { title: "Preparing PLY", detail: "Filtering Gaussians", progress: 45, stageLabel: "STAGE 2 / 4 路 CPU" });
|
|
|
|
| 1308 |
client.predict("/export_ply", { artifact_url: artifactUrl })
|
| 1309 |
);
|
| 1310 |
const plyUrl = plyWrap.result.data[0].url;
|
| 1311 |
+
const plySize = plyWrap.result.data[0].size;
|
| 1312 |
+
setStage("ply", "done", fmtBytes(plySize));
|
| 1313 |
setDownload(dlPly, plyUrl, "Download PLY");
|
| 1314 |
+
document.getElementById("telPly").textContent = fmtBytes(plySize);
|
| 1315 |
+
logLine("ply", "ok", `${fmtSec(plyWrap.ms / 1000)} 路 ${fmtBytes(plySize)}`);
|
| 1316 |
|
| 1317 |
// Stage 3: Viewer
|
| 1318 |
setViewerState("loading", { title: "Encoding viewer", detail: "Building WebGL scene", progress: 70, stageLabel: "STAGE 3 / 4 路 ENCODE" });
|
|
|
|
| 1322 |
client.predict("/export_viewer", { scene_ply_url: plyUrl })
|
| 1323 |
);
|
| 1324 |
const viewerUrl = viewWrap.result.data[0].url + "?v=" + Date.now();
|
| 1325 |
+
const viewerSize = viewWrap.result.data[0].size;
|
| 1326 |
+
setStage("viewer", "done", fmtBytes(viewerSize));
|
| 1327 |
+
document.getElementById("telViewer").textContent = fmtBytes(viewerSize);
|
| 1328 |
viewerFrame.src = viewerUrl;
|
| 1329 |
viewerFrame.onload = () => {
|
| 1330 |
viewerFrame.classList.add("ready");
|
| 1331 |
setViewerState("ready");
|
| 1332 |
viewportMeta.textContent = "ready";
|
| 1333 |
};
|
| 1334 |
+
logLine("viewer", "ok", `${fmtSec(viewWrap.ms / 1000)} 路 ${fmtBytes(viewerSize)}`);
|
| 1335 |
|
| 1336 |
// Stage 4: HTML
|
| 1337 |
setViewerState("loading", { title: "Bundling HTML", detail: "Embedding assets for download", progress: 92, stageLabel: "STAGE 4 / 4 路 BUNDLE" });
|
|
|
|
| 1341 |
client.predict("/export_html", { viewer_html_url: viewerUrl.replace(/[?#].*/, "") })
|
| 1342 |
);
|
| 1343 |
const htmlUrl = htmlWrap.result.data[0].url;
|
| 1344 |
+
const htmlSize = htmlWrap.result.data[0].size;
|
| 1345 |
+
setStage("html", "done", fmtBytes(htmlSize));
|
| 1346 |
setDownload(dlHtml, htmlUrl, "Download HTML");
|
| 1347 |
|
| 1348 |
const totalSec = (performance.now() - pipelineStart) / 1000;
|
| 1349 |
document.getElementById("telTotal").textContent = fmtSec(totalSec);
|
| 1350 |
+
logLine("html", "ok", `${fmtSec(htmlWrap.ms / 1000)} 路 ${fmtBytes(htmlSize)}`);
|
| 1351 |
|
| 1352 |
setViewerState("ready");
|
| 1353 |
setStatus("idle", { gpu: "idle", queue: 0, stage: "4 / 4" });
|