"""Gradio 5 UI for Simam Splat Surgeon. The heavyweight reconstruction/rendering stack is deliberately not imported. This Space is a transparent, CPU-safe PLY editing baseline that can be used to inspect and prune real Gaussian exports before a renderer-specific handoff. """ from __future__ import annotations import uuid from pathlib import Path try: from .surgeon import EditConfig, load_ply, edit_cloud, render_orbit_gif, save_ply, write_manifest except ImportError: # Running `python app.py` inside a Hugging Face Space. from surgeon import EditConfig, load_ply, edit_cloud, render_orbit_gif, save_ply, write_manifest ROOT = Path(__file__).resolve().parent FIXTURE = ROOT / "examples" / "synthetic_cloud.ply" def _float_or_none(value: object) -> float | None: if value is None or str(value).strip() == "": return None return float(value) def _triplet(values: tuple[object, object, object]) -> tuple[float, float, float] | None: parsed = tuple(_float_or_none(value) for value in values) return None if all(value is None for value in parsed) else tuple(value or 0.0 for value in parsed) # type: ignore[return-value] def _source_path(upload: object) -> Path: if upload is None: return FIXTURE if isinstance(upload, dict): upload = upload.get("path") or upload.get("name") if isinstance(upload, (list, tuple)): upload = upload[0] if upload else None return Path(str(upload)) if upload else FIXTURE def process( upload: object, point_budget: int, confidence_threshold: float, color_mode: str, crop_x_min: object, crop_x_max: object, crop_y_min: object, crop_y_max: object, crop_z_min: object, crop_z_max: object, mask_mode: str, mask_x: float, mask_y: float, mask_z: float, mask_radius: float, mask_x_min: float, mask_x_max: float, mask_y_min: float, mask_y_max: float, mask_z_min: float, mask_z_max: float, ): source = _source_path(upload) cloud = load_ply(source) config = EditConfig( point_budget=int(point_budget), confidence_threshold=float(confidence_threshold), crop_min=_triplet((crop_x_min, crop_y_min, crop_z_min)), crop_max=_triplet((crop_x_max, crop_y_max, crop_z_max)), color_mode=color_mode, mask_mode=mask_mode, mask_center=(float(mask_x), float(mask_y), float(mask_z)), mask_radius=float(mask_radius), mask_min=(float(mask_x_min), float(mask_y_min), float(mask_z_min)), mask_max=(float(mask_x_max), float(mask_y_max), float(mask_z_max)), ) edited, manifest = edit_cloud(cloud, config) # Keep outputs under the Space directory so Gradio can serve them reliably # on hosted and local runtimes without relying on platform-specific temp ACLs. workdir = ROOT / "outputs" / uuid.uuid4().hex workdir.mkdir(parents=True, exist_ok=True) output_ply = save_ply(edited, workdir / "cleaned_splats.ply") manifest_path = write_manifest(manifest, workdir / "edit_manifest.json") preview_path = render_orbit_gif(edited, color_mode, workdir / "orbit_preview.gif") diagnostics = ( f"### Edit complete\n" f"- **Source:** `{source.name}`\n" f"- **Points:** `{manifest['input_points']:,}` -> `{manifest['output_points']:,}`\n" f"- **Retention stages:** confidence `{manifest['retention']['after_confidence']:,}`, " f"crop `{manifest['retention']['after_crop']:,}`, mask `{manifest['retention']['after_mask']:,}`\n" f"- **Preview:** orbit GIF colored by **{color_mode}** (display-only)\n\n" f"> This is a CPU-safe point-cloud editing baseline. It does not render Gaussian covariance/SH or infer semantic labels." ) return str(output_ply), str(manifest_path), str(preview_path), diagnostics def build_demo(): try: import gradio as gr except ImportError as exc: raise RuntimeError("Install requirements.txt to launch the Gradio Space") from exc css = """ .gradio-container { max-width: 1180px !important; } .hero { border: 1px solid #263752; border-radius: 18px; padding: 22px 26px; background: linear-gradient(120deg,#101a31,#152940); } .hero h1 { letter-spacing: -0.04em; margin-bottom: 6px; } """ with gr.Blocks(title="Simam Splat Surgeon", theme=gr.themes.Soft(primary_hue="cyan"), css=css) as demo: gr.Markdown( "# Simam Splat Surgeon\n" "### Inspect, prune, and export Gaussian/point-cloud PLYs — safely on CPU\n\n" "Upload a PLY or run the built-in synthetic fixture. The editor keeps scalar Gaussian fields intact, " "applies transparent confidence/crop/mask rules, and emits a cleaned PLY plus a reproducible JSON manifest.\n\n" "> **Baseline label:** no learned semantics and no full Gaussian renderer are required or claimed.", elem_classes="hero", ) with gr.Row(): with gr.Column(scale=1): upload = gr.File(label="Input PLY (optional)", file_types=[".ply"], type="filepath") gr.Markdown("Leave empty to use `examples/synthetic_cloud.ply`.") point_budget = gr.Slider(100, 20000, value=5000, step=100, label="Point budget / LOD") confidence = gr.Slider(0, 1, value=0.05, step=0.01, label="Confidence threshold") color_mode = gr.Radio(["source", "confidence", "height", "grayscale"], value="source", label="Preview color mode") with gr.Column(scale=1): gr.Markdown("#### Crop / clip bounds\nLeave all six blank to keep the full scene.") with gr.Row(): crop_x_min = gr.Number(label="X min", value=None) crop_x_max = gr.Number(label="X max", value=None) with gr.Row(): crop_y_min = gr.Number(label="Y min", value=None) crop_y_max = gr.Number(label="Y max", value=None) with gr.Row(): crop_z_min = gr.Number(label="Z min", value=None) crop_z_max = gr.Number(label="Z max", value=None) mask_mode = gr.Dropdown(["none", "sphere", "box"], value="none", label="Region mask") with gr.Row(): mask_x = gr.Number(label="Mask X", value=0) mask_y = gr.Number(label="Mask Y", value=0) mask_z = gr.Number(label="Mask Z", value=0) mask_radius = gr.Number(label="Sphere radius", value=1.0) gr.Markdown("Box mask bounds (used only when region mask = `box`)") with gr.Row(): mask_x_min = gr.Number(label="BX min", value=-1) mask_x_max = gr.Number(label="BX max", value=1) with gr.Row(): mask_y_min = gr.Number(label="BY min", value=-1) mask_y_max = gr.Number(label="BY max", value=1) with gr.Row(): mask_z_min = gr.Number(label="BZ min", value=-1) mask_z_max = gr.Number(label="BZ max", value=1) run = gr.Button("Surgically edit PLY", variant="primary") with gr.Row(): cleaned = gr.File(label="Cleaned PLY") manifest = gr.File(label="Edit manifest") preview = gr.Image(label="Shareable orbit preview", type="filepath") diagnostics = gr.Markdown() inputs = [upload, point_budget, confidence, color_mode, crop_x_min, crop_x_max, crop_y_min, crop_y_max, crop_z_min, crop_z_max, mask_mode, mask_x, mask_y, mask_z, mask_radius, mask_x_min, mask_x_max, mask_y_min, mask_y_max, mask_z_min, mask_z_max] run.click(process, inputs=inputs, outputs=[cleaned, manifest, preview, diagnostics]) gr.Examples([[None, 5000, 0.05, "confidence", None, None, None, None, None, None, "none", 0, 0, 0, 1, -1, 1, -1, 1, -1, 1]], inputs=inputs, label="Built-in example") gr.Markdown( "### Research and limitations\n" "This demo is a reproducible editing baseline for semantic/uncertainty-aware splat tooling. " "Read the [research note](research_note.md) for the proposed evaluation protocol and the explicit boundary " "between confidence heuristics and learned semantics. Do not treat a filtered point cloud as a photorealistic render." ) return demo if __name__ == "__main__": build_demo().launch()