first commit

This commit is contained in:
ykcheungab
2026-08-06 15:18:27 +08:00
commit a5a73d76d1
37 changed files with 2697 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# Sensor Bench EXE Build
This folder contains the Windows PyInstaller build setup for Sensor Bench.
## Requirements
- Windows x64
- Anaconda or Miniconda available as `conda`
- Python 3.10 build environment
- Internet access to install `orisys` from PyPI
The build installs `orisys` from PyPI. Do not use `PYTHONPATH` or an editable `orisys-sdk` checkout for release builds.
## Build
From the repository root (cmd or PowerShell):
```bat
.\build\create_env.bat
.\build\build_exe.bat
```
The `.bat` wrappers bypass the local PowerShell execution policy. If you prefer calling PowerShell directly:
```bat
powershell -NoProfile -ExecutionPolicy Bypass -File .\build\create_env.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\build\build_exe.ps1
```
Output:
```text
dist/SensorBench/SensorBench.exe
```
The build is `onedir` rather than `onefile` so startup is faster and bundled DLL/resource issues are easier to diagnose.
## Validation
The build script runs:
```powershell
python tests/test_smoke.py
python build/verify_dist.py
```
Manual hardware check:
1. Run `dist\SensorBench\SensorBench.exe`.
2. Confirm the UI opens without setting `PYTHONPATH`.
3. Confirm the UI defaults to Simplified Chinese and can switch to English.
4. Confirm Orisys status is available and fixed mode shows DDJX01.
5. Use Next / Revert / New Sample Reset on the left workflow panel.
6. Start preview with camera index `0`.
7. Confirm raw preview and processed preview update.
8. Record a short clip and verify it appears under `dist\SensorBench\recordings`.
Locale files are bundled under `_internal/config/locales/` (and can also be placed beside the EXE under `config/locales/` for overrides). Edit those JSON files to change operator-facing text without rebuilding.
+3
View File
@@ -0,0 +1,3 @@
@echo off
cd /d "%~dp0.."
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0build_exe.ps1" %*
+42
View File
@@ -0,0 +1,42 @@
param(
[string]$EnvName = "sensor-bench-build-py310"
)
$ErrorActionPreference = "Stop"
$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
$DistDir = Join-Path $RepoRoot "dist"
$WorkDir = Join-Path $RepoRoot "build\pyinstaller_work"
$SpecPath = Join-Path $PSScriptRoot "sensor_bench.spec"
if (-not (Get-Command conda -ErrorAction SilentlyContinue)) {
throw "conda was not found on PATH. Open an Anaconda Prompt or initialize conda for PowerShell."
}
Push-Location $RepoRoot
try {
conda run -n $EnvName python -m pip install --upgrade pip
conda run -n $EnvName python -m pip install -e ".[pack]"
conda run -n $EnvName python -m pip install --upgrade orisys
conda run -n $EnvName python tests/test_smoke.py
if (Test-Path $WorkDir) {
Remove-Item -Recurse -Force $WorkDir
}
if (Test-Path (Join-Path $DistDir "SensorBench")) {
Remove-Item -Recurse -Force (Join-Path $DistDir "SensorBench")
}
conda run -n $EnvName python -m PyInstaller --noconfirm --clean --distpath "$DistDir" --workpath "$WorkDir" "$SpecPath"
Copy-Item -Recurse -Force (Join-Path $RepoRoot "config") (Join-Path $DistDir "SensorBench")
Copy-Item -Recurse -Force (Join-Path $RepoRoot "steps") (Join-Path $DistDir "SensorBench")
conda run -n $EnvName python build/verify_dist.py
Write-Host "Build complete: dist\SensorBench\SensorBench.exe"
}
finally {
Pop-Location
}
+3
View File
@@ -0,0 +1,3 @@
@echo off
cd /d "%~dp0.."
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0create_env.ps1" %*
+30
View File
@@ -0,0 +1,30 @@
param(
[string]$EnvName = "sensor-bench-build-py310",
[string]$PythonVersion = "3.10"
)
$ErrorActionPreference = "Stop"
$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
if (-not (Get-Command conda -ErrorAction SilentlyContinue)) {
throw "conda was not found on PATH. Open an Anaconda Prompt or initialize conda for PowerShell."
}
$envList = conda env list | Out-String
if ($envList -notmatch "(?m)^\s*$([regex]::Escape($EnvName))\s") {
conda create -y -n $EnvName python=$PythonVersion
}
conda run -n $EnvName python -m pip install --upgrade pip
Push-Location $RepoRoot
try {
conda run -n $EnvName python -m pip install -e ".[pack]"
}
finally {
Pop-Location
}
Write-Host "Build environment ready: $EnvName"
Write-Host "Orisys will be installed from PyPI by build_exe.ps1."
+98
View File
@@ -0,0 +1,98 @@
# -*- mode: python ; coding: utf-8 -*-
from pathlib import Path
from PyInstaller.utils.hooks import collect_all, collect_submodules
repo_root = Path.cwd()
src_dir = repo_root / "src"
work_dir = repo_root / "build" / "pyinstaller_work"
datas = [
(str(repo_root / "config"), "config"),
(str(repo_root / "steps"), "steps"),
]
binaries = []
hiddenimports = [
"sensor_bench.main",
"sensor_bench.app",
"sensor_bench.acquisition",
"sensor_bench.config_loader",
"sensor_bench.i18n",
"sensor_bench.paths",
"sensor_bench.plot_history",
"sensor_bench.recorder",
"orisys",
"orisys_blend",
"scipy.fft",
"scipy.ndimage",
"scipy.sparse.linalg",
"numba",
"llvmlite",
]
for package in ("PyQt5", "pyqtgraph", "cv2", "orisys", "orisys_blend", "numba", "llvmlite"):
pkg_datas, pkg_binaries, pkg_hidden = collect_all(package)
datas += pkg_datas
binaries += pkg_binaries
hiddenimports += pkg_hidden
hiddenimports += collect_submodules("orisys_blend")
excludes = [
"cupy",
"cupyx",
"pyopencl",
"open3d",
"matplotlib",
"tkinter",
"pytest",
"pip",
"wheel",
]
a = Analysis(
[str(repo_root / "run.py")],
pathex=[str(repo_root), str(src_dir)],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=excludes,
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name="SensorBench",
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name="SensorBench",
)
+1
View File
@@ -0,0 +1 @@
Binary file not shown.
+31
View File
@@ -0,0 +1,31 @@
"""Verify the PyInstaller onedir output has the expected portable layout."""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
DIST = ROOT / "dist" / "SensorBench"
def require(path: Path) -> None:
if not path.exists():
raise FileNotFoundError(f"Missing build artifact: {path}")
def main() -> int:
require(DIST / "SensorBench.exe")
require(DIST / "config" / "options.json")
require(DIST / "config" / "locales" / "zh_CN.json")
require(DIST / "config" / "locales" / "en_US.json")
require(DIST / "steps" / "default.json")
require(DIST / "_internal")
print(f"Verified SensorBench dist layout: {DIST}")
return 0
if __name__ == "__main__":
raise SystemExit(main())