From 3435f33697f40c956af9be72700fead2980fea45 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Mon, 24 Aug 2026 17:17:51 +0800
Subject: [PATCH] fix: validate empty point-cloud inference inputs

---
 scripts/serve_workbench_console.py |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/scripts/serve_workbench_console.py b/scripts/serve_workbench_console.py
index 94ba5cb..65cd83f 100644
--- a/scripts/serve_workbench_console.py
+++ b/scripts/serve_workbench_console.py
@@ -496,6 +496,31 @@
         return dict(value) if value else None
 
 
+def validate_pointcloud_model_input(path: Path) -> None:
+    """Reject obviously incomplete uploads before consuming a CPU inference job."""
+    size = path.stat().st_size
+    if size < 1:
+        raise ApiError("点云文件为空。请选择包含 RGB 点位的完整点云导出文件。")
+    if path.suffix.lower() not in {".las", ".laz"}:
+        return
+    if size < 227:
+        raise ApiError("LAS/LAZ 文件不完整(小于有效 LAS 文件头)。请选择完整点云文件,不要上传空白或未完成下载的分块。")
+    with path.open("rb") as stream:
+        header = stream.read(375)
+    if len(header) < 227 or header[:4] != b"LASF":
+        raise ApiError("LAS/LAZ 文件头无效。请选择完整的 LAS/LAZ 点云导出文件。")
+    header_size = int.from_bytes(header[94:96], "little")
+    if header_size < 227 or header_size > size:
+        raise ApiError("LAS/LAZ 文件头不完整。请选择完整的 LAS/LAZ 点云导出文件。")
+    version_minor = header[25]
+    point_count_offset, point_count_size = (247, 8) if version_minor >= 4 else (107, 4)
+    if len(header) < point_count_offset + point_count_size:
+        raise ApiError("LAS/LAZ 文件头不完整。请选择完整的 LAS/LAZ 点云导出文件。")
+    point_count = int.from_bytes(header[point_count_offset:point_count_offset + point_count_size], "little")
+    if point_count < 1:
+        raise ApiError("LAS/LAZ 文件没有点记录。请选择包含实际 RGB 点位的完整点云文件,而不是空分块。")
+
+
 def execute_pointcloud_inference_job(root: Path, job_id: str, model: Path, source: Path, output: Path) -> None:
     with POINTCLOUD_INFERENCE_JOBS_LOCK:
         POINTCLOUD_INFERENCE_JOBS[job_id].update({"status": "running", "stage": "inference", "startedAt": datetime.now(UTC).isoformat()})
@@ -1709,6 +1734,7 @@
         suffixes = {".ply", ".pcd", ".xyz", ".xyzn", ".xyzrgb", ".las", ".laz"}
         if Path(name).suffix.lower() not in suffixes:
             raise ApiError("Model inference requires a PLY, PCD, XYZ, LAS, or LAZ point cloud.")
+        validate_pointcloud_model_input(staged_path)
         python = self.root / ".venvs" / "05-3d-pointcloud" / "Scripts" / "python.exe"
         if not python.is_file():
             raise ApiError("3D point-cloud virtual environment is unavailable. Run the capability setup first.")

--
Gitblit v1.9.3