"""Gradio application for single-image height estimation. The demo is a thin wrapper around two things that already exist in this repo and are shared with the offline CLI, so the Space cannot drift from the numbers the CLI reports: * `infer/` + `dwdata/` — the model and the exact preprocessing contract stored in the checkpoint. * `viz/` and `viewer/` — the visualisation layer: the figure primitives (`viz.figures`), the mesh writers (`viz.mesh`), and the standalone dual-pane DSM inspector (`viewer/index.html` + `viewer/app.js`), which is inlined into an iframe here and works identically opened straight off disk. The viewer is *not* re-implemented for the Space. `viewer/index.html` is read at import time and its `', f'\n' '', ) def inline(match: "re.Match[str]") -> str: src = match.group(1) js = (_VIEWER_ROOT / src).read_text(encoding="utf-8") # a literal \n" + js.replace("" document, n = re.subn(r'', inline, document) if n < 4: # three.js, OrbitControls, PointerLockControls, app.js raise RuntimeError(f"viewer/index.html: inlined only {n} of 4 scripts") if _PAYLOAD_SLOT not in document: raise RuntimeError("viewer/index.html: no slot for the prediction payload") return document _VIEWER_SHELL = _build_viewer_shell() def _png_data_url(image: Image.Image) -> str: buffer = io.BytesIO() image.save(buffer, format="PNG", optimize=True) encoded = base64.b64encode(buffer.getvalue()).decode("ascii") return f"data:image/png;base64,{encoded}" def _viewer(payload: dict) -> str: # `<` never appears outside a JSON string, so escaping it is enough to make # the blob inert inside the