|
| 1 | +@echo off |
| 2 | +REM deploy.bat — Zero-assumption bootstrapper for Depth Estimation Skill (Windows) |
| 3 | +REM |
| 4 | +REM Probes the system for Python, GPU backends, and installs the minimum |
| 5 | +REM viable stack. Called by Aegis skill-runtime-manager during installation. |
| 6 | +REM |
| 7 | +REM Uses skills\lib\env_config.py for hardware detection. |
| 8 | +REM |
| 9 | +REM Exit codes: |
| 10 | +REM 0 = success |
| 11 | +REM 1 = fatal error (no Python found) |
| 12 | +REM 2 = partial success (CPU-only fallback) |
| 13 | + |
| 14 | +setlocal enabledelayedexpansion |
| 15 | + |
| 16 | +set "SKILL_DIR=%~dp0" |
| 17 | +REM Remove trailing backslash |
| 18 | +if "%SKILL_DIR:~-1%"=="\" set "SKILL_DIR=%SKILL_DIR:~0,-1%" |
| 19 | +set "VENV_DIR=%SKILL_DIR%\.venv" |
| 20 | +set "LOG_PREFIX=[Depth-deploy]" |
| 21 | + |
| 22 | +REM Resolve lib dir (two levels up + lib) |
| 23 | +set "LIB_DIR=" |
| 24 | +if exist "%SKILL_DIR%\..\..\lib\env_config.py" ( |
| 25 | + pushd "%SKILL_DIR%\..\..\lib" |
| 26 | + set "LIB_DIR=!CD!" |
| 27 | + popd |
| 28 | +) |
| 29 | + |
| 30 | +REM ─── Step 1: Find Python ─────────────────────────────────────────────────── |
| 31 | + |
| 32 | +echo %LOG_PREFIX% Searching for Python...>&2 |
| 33 | + |
| 34 | +set "PYTHON_CMD=" |
| 35 | + |
| 36 | +REM Try the Windows Python launcher (py.exe) first — ships with python.org installer |
| 37 | +for %%V in (3.12 3.11 3.10 3.9) do ( |
| 38 | + if not defined PYTHON_CMD ( |
| 39 | + py -%%V --version >nul 2>&1 |
| 40 | + if !errorlevel! equ 0 ( |
| 41 | + set "PYTHON_CMD=py -%%V" |
| 42 | + ) |
| 43 | + ) |
| 44 | +) |
| 45 | + |
| 46 | +REM Fallback: bare python3 / python on PATH |
| 47 | +if not defined PYTHON_CMD ( |
| 48 | + python3 --version >nul 2>&1 |
| 49 | + if !errorlevel! equ 0 ( |
| 50 | + REM Verify version >= 3.9 |
| 51 | + for /f "tokens=2 delims= " %%A in ('python3 --version 2^>^&1') do set "_pyver=%%A" |
| 52 | + for /f "tokens=1,2 delims=." %%A in ("!_pyver!") do ( |
| 53 | + if %%A geq 3 if %%B geq 9 set "PYTHON_CMD=python3" |
| 54 | + ) |
| 55 | + ) |
| 56 | +) |
| 57 | + |
| 58 | +if not defined PYTHON_CMD ( |
| 59 | + python --version >nul 2>&1 |
| 60 | + if !errorlevel! equ 0 ( |
| 61 | + for /f "tokens=2 delims= " %%A in ('python --version 2^>^&1') do set "_pyver=%%A" |
| 62 | + for /f "tokens=1,2 delims=." %%A in ("!_pyver!") do ( |
| 63 | + if %%A geq 3 if %%B geq 9 set "PYTHON_CMD=python" |
| 64 | + ) |
| 65 | + ) |
| 66 | +) |
| 67 | + |
| 68 | +if not defined PYTHON_CMD ( |
| 69 | + echo %LOG_PREFIX% ERROR: No Python ^>=3.9 found. Install Python 3.9+ and retry.>&2 |
| 70 | + echo {"event": "error", "stage": "python", "message": "No Python >=3.9 found"} |
| 71 | + exit /b 1 |
| 72 | +) |
| 73 | + |
| 74 | +for /f "tokens=*" %%A in ('!PYTHON_CMD! --version 2^>^&1') do set "PY_VERSION=%%A" |
| 75 | +echo %LOG_PREFIX% Using Python: %PYTHON_CMD% (%PY_VERSION%)>&2 |
| 76 | +echo {"event": "progress", "stage": "python", "message": "Found %PY_VERSION%"} |
| 77 | + |
| 78 | +REM ─── Step 2: Create virtual environment ──────────────────────────────────── |
| 79 | + |
| 80 | +if not exist "%VENV_DIR%\Scripts\python.exe" ( |
| 81 | + echo %LOG_PREFIX% Creating virtual environment...>&2 |
| 82 | + %PYTHON_CMD% -m venv "%VENV_DIR%" |
| 83 | + if !errorlevel! neq 0 ( |
| 84 | + echo %LOG_PREFIX% ERROR: Failed to create virtual environment>&2 |
| 85 | + echo {"event": "error", "stage": "venv", "message": "Failed to create venv"} |
| 86 | + exit /b 1 |
| 87 | + ) |
| 88 | +) |
| 89 | + |
| 90 | +set "PIP=%VENV_DIR%\Scripts\pip.exe" |
| 91 | +set "VPYTHON=%VENV_DIR%\Scripts\python.exe" |
| 92 | + |
| 93 | +"%PIP%" install --upgrade pip -q >nul 2>&1 |
| 94 | + |
| 95 | +echo {"event": "progress", "stage": "venv", "message": "Virtual environment ready"} |
| 96 | + |
| 97 | +REM ─── Step 2.5: Bundle env_config.py alongside transform.py ───────────────── |
| 98 | + |
| 99 | +if defined LIB_DIR ( |
| 100 | + if exist "%LIB_DIR%\env_config.py" ( |
| 101 | + copy /Y "%LIB_DIR%\env_config.py" "%SKILL_DIR%\scripts\env_config.py" >nul 2>&1 |
| 102 | + echo %LOG_PREFIX% Bundled env_config.py into scripts\>&2 |
| 103 | + ) |
| 104 | +) |
| 105 | + |
| 106 | +REM ─── Step 3: Detect hardware via env_config ──────────────────────────────── |
| 107 | + |
| 108 | +set "BACKEND=cpu" |
| 109 | + |
| 110 | +REM Find env_config.py — bundled copy or repo lib\ |
| 111 | +set "ENV_CONFIG_DIR=" |
| 112 | +if exist "%SKILL_DIR%\scripts\env_config.py" ( |
| 113 | + set "ENV_CONFIG_DIR=%SKILL_DIR%\scripts" |
| 114 | +) else if defined LIB_DIR ( |
| 115 | + if exist "%LIB_DIR%\env_config.py" ( |
| 116 | + set "ENV_CONFIG_DIR=%LIB_DIR%" |
| 117 | + ) |
| 118 | +) |
| 119 | + |
| 120 | +if defined ENV_CONFIG_DIR ( |
| 121 | + echo %LOG_PREFIX% Detecting hardware via env_config.py...>&2 |
| 122 | + |
| 123 | + REM Run env_config detection via Python (temp file avoids for /f quoting issues) |
| 124 | + set "ENV_CONFIG_DIR=!ENV_CONFIG_DIR!" |
| 125 | + set "_TMPBACK=%TEMP%\_aegis_detect_backend.txt" |
| 126 | + "%VPYTHON%" -c "import sys,os; sys.path.insert(0, os.environ['ENV_CONFIG_DIR']); from env_config import HardwareEnv; env = HardwareEnv.detect(); print(env.backend)" > "!_TMPBACK!" 2>nul |
| 127 | + if exist "!_TMPBACK!" ( |
| 128 | + set /p DETECTED_BACKEND=<"!_TMPBACK!" |
| 129 | + del "!_TMPBACK!" 2>nul |
| 130 | + ) |
| 131 | + |
| 132 | + REM Validate backend value (Windows: only cuda, intel, cpu are realistic) |
| 133 | + if "!DETECTED_BACKEND!"=="cuda" ( |
| 134 | + set "BACKEND=cuda" |
| 135 | + ) else if "!DETECTED_BACKEND!"=="intel" ( |
| 136 | + set "BACKEND=intel" |
| 137 | + ) else if "!DETECTED_BACKEND!"=="cpu" ( |
| 138 | + set "BACKEND=cpu" |
| 139 | + ) else ( |
| 140 | + echo %LOG_PREFIX% env_config returned '!DETECTED_BACKEND!', falling back to heuristic>&2 |
| 141 | + set "BACKEND=cpu" |
| 142 | + ) |
| 143 | + |
| 144 | + echo %LOG_PREFIX% env_config detected backend: !BACKEND!>&2 |
| 145 | +) else ( |
| 146 | + echo %LOG_PREFIX% env_config.py not found, using heuristic detection...>&2 |
| 147 | + |
| 148 | + REM Fallback: inline GPU detection via nvidia-smi |
| 149 | + where nvidia-smi >nul 2>&1 |
| 150 | + if !errorlevel! equ 0 ( |
| 151 | + for /f "tokens=*" %%G in ('nvidia-smi --query-gpu^=driver_version --format^=csv^,noheader 2^>nul') do ( |
| 152 | + if not "%%G"=="" ( |
| 153 | + set "BACKEND=cuda" |
| 154 | + echo %LOG_PREFIX% Detected NVIDIA GPU ^(driver: %%G^)>&2 |
| 155 | + ) |
| 156 | + ) |
| 157 | + ) |
| 158 | +) |
| 159 | + |
| 160 | +echo {"event": "progress", "stage": "gpu", "backend": "!BACKEND!", "message": "Compute backend: !BACKEND!"} |
| 161 | + |
| 162 | +REM ─── Step 4: Install requirements ────────────────────────────────────────── |
| 163 | + |
| 164 | +set "REQ_FILE=%SKILL_DIR%\requirements_!BACKEND!.txt" |
| 165 | + |
| 166 | +if not exist "!REQ_FILE!" ( |
| 167 | + echo %LOG_PREFIX% WARNING: !REQ_FILE! not found, falling back to CPU>&2 |
| 168 | + set "REQ_FILE=%SKILL_DIR%\requirements_cpu.txt" |
| 169 | + set "BACKEND=cpu" |
| 170 | +) |
| 171 | + |
| 172 | +echo %LOG_PREFIX% Installing dependencies from !REQ_FILE! ...>&2 |
| 173 | +echo {"event": "progress", "stage": "install", "message": "Installing !BACKEND! dependencies..."} |
| 174 | + |
| 175 | +if "!BACKEND!"=="cuda" ( |
| 176 | + REM CUDA on Windows: install torch with CUDA index, then remaining deps |
| 177 | + "%PIP%" install torch torchvision --index-url https://download.pytorch.org/whl/cu124 -q 2>&1 | findstr /V "^$" >nul |
| 178 | + if !errorlevel! neq 0 ( |
| 179 | + echo %LOG_PREFIX% WARNING: CUDA torch install failed, trying cu121...>&2 |
| 180 | + "%PIP%" install torch torchvision --index-url https://download.pytorch.org/whl/cu121 -q 2>&1 | findstr /V "^$" >nul |
| 181 | + ) |
| 182 | + REM Install remaining requirements (depth-anything-v2, tensorrt, etc.) |
| 183 | + "%PIP%" install -r "!REQ_FILE!" -q 2>&1 | findstr /V "^$" >nul |
| 184 | +) else ( |
| 185 | + "%PIP%" install -r "!REQ_FILE!" -q 2>&1 | findstr /V "^$" >nul |
| 186 | +) |
| 187 | + |
| 188 | +REM ─── Step 5: Pre-build TensorRT engine (CUDA only) ───────────────────────── |
| 189 | + |
| 190 | +if "!BACKEND!"=="cuda" ( |
| 191 | + echo %LOG_PREFIX% Pre-building TensorRT FP16 engine ^(30-120s one-time build^)...>&2 |
| 192 | + echo {"event": "progress", "stage": "optimize", "message": "Building TensorRT FP16 engine (~30-120s)..."} |
| 193 | + |
| 194 | + "%VPYTHON%" -c "import sys,os; sys.path.insert(0, '%SKILL_DIR%\\scripts'); from transform import DepthEstimationSkill, PYTORCH_CONFIGS, TRT_CACHE_DIR; import torch; gpu_tag = torch.cuda.get_device_name(0).replace(' ', '_').lower(); cfg = PYTORCH_CONFIGS['depth-anything-v2-small']; engine_path = TRT_CACHE_DIR / f'{cfg[\"filename\"].replace(\".pth\", \"\")}_fp16_{gpu_tag}.trt'; print(f'Engine exists: {engine_path.exists()}') if engine_path.exists() else None; skill = DepthEstimationSkill(); config = {'model': 'depth-anything-v2-small', 'device': 'auto', 'colormap': 'inferno', 'blend_mode': 'depth_only'}; info = skill._load_tensorrt('depth-anything-v2-small', config); print(f'TensorRT engine built: {info}')" 2>&1 |
| 195 | + |
| 196 | + if !errorlevel! equ 0 ( |
| 197 | + echo {"event": "progress", "stage": "optimize", "message": "TensorRT engine built successfully"} |
| 198 | + ) else ( |
| 199 | + echo %LOG_PREFIX% WARNING: TensorRT build failed, will use PyTorch CUDA at runtime>&2 |
| 200 | + echo {"event": "progress", "stage": "optimize", "message": "TensorRT build failed — PyTorch CUDA fallback"} |
| 201 | + ) |
| 202 | +) |
| 203 | + |
| 204 | +REM ─── Step 6: Verify installation ─────────────────────────────────────────── |
| 205 | + |
| 206 | +echo %LOG_PREFIX% Verifying installation...>&2 |
| 207 | + |
| 208 | +if defined ENV_CONFIG_DIR ( |
| 209 | + "%VPYTHON%" -c "import sys,os,json; sys.path.insert(0, os.environ['ENV_CONFIG_DIR']); from env_config import HardwareEnv; env = HardwareEnv.detect(); print(json.dumps(env.to_dict(), indent=2))" 2>&1 |
| 210 | +) else ( |
| 211 | + "%VPYTHON%" -c "import torch; print(f'torch={torch.__version__}, CUDA={torch.cuda.is_available()}')" 2>&1 |
| 212 | +) |
| 213 | + |
| 214 | +"%VPYTHON%" -c "import sys; sys.path.insert(0, '%SKILL_DIR%\\scripts'); from transform import DepthEstimationSkill; print('transform.py: OK')" 2>&1 |
| 215 | +if !errorlevel! neq 0 ( |
| 216 | + echo %LOG_PREFIX% WARNING: transform.py import check failed>&2 |
| 217 | +) |
| 218 | + |
| 219 | +echo {"event": "complete", "backend": "!BACKEND!", "message": "Depth Estimation skill installed (!BACKEND! backend)"} |
| 220 | +echo %LOG_PREFIX% Done! Backend: !BACKEND!>&2 |
| 221 | + |
| 222 | +endlocal |
| 223 | +exit /b 0 |
0 commit comments