improve node_modules cross-platform management with tag-based swapping and add Linux CUDA backend support via automated source builds.

This commit is contained in:
howwonder committed 2026-06-14 12:34:22 +05:30
1 parent 54f4809990
commit 98c65fc610
5 files changed
+206 -37

No files matched your search

+20 -11
View File
@@ -36,13 +36,14 @@
### Linux
1. **Check compatibility:** Prebuilt Linux backends are built on Ubuntu 24.04 and require **glibc 2.38+**. Run `ldd --version` to verify.
2. **Launch:** Open a terminal in the project folder and run **`./linux.sh`** (downloads portable Node.js and pre-compiled GPU backend binaries on first run).
- NVIDIA GPU users will be prompted if they want to set up the high-performance **CUDA** backend (which attempts to download a prebuilt binary first and automatically compiles from source as a fallback if conflicts are found).
- For maximum AMD GPU performance, use **`./linux.sh --max-perf`** on first setup (adds the ROCm backend).
- For Intel Core Ultra NPU support, install the Intel Linux NPU driver, then run **`./linux.sh --setup-openvino`**.
3. **Add Models:** Drop `.safetensors`, `.gguf`, or `.ckpt` weights into `app/models/` (or download them via the **Model Manager** tab in the UI).
4. **Generate:** Open `http://localhost:1420` in your browser, select your model, and write a prompt.
### macOS
1. **Check compatibility:** The prebuilt macOS backend is for **Apple Silicon (M1 or newer)** and uses **Metal** GPU acceleration.
1. **Check compatibility:** The prebuilt macOS backend is for **Apple Silicon (M1 or newer)** and uses **Metal** GPU acceleration. *(Note: macOS Intel hardware is completely unsupported and has not been tested.)*
2. **Launch:** Open Terminal in the project folder and run **`./mac.sh`** (downloads portable Node.js and the pre-compiled Metal backend on first run).
3. **Add Models:** Drop `.safetensors`, `.gguf`, or `.ckpt` weights into `app/models/` (or download them via the **Model Manager** tab in the UI).
4. **Generate:** Open `http://localhost:1420` in your browser, select your model, and write a prompt.
@@ -98,7 +99,7 @@ local-ai-image-generator/
| GPU Vendor | Primary | Fallback | Notes |
| :--- | :--- | :--- | :--- |
| **NVIDIA** | Vulkan | CPU | No reliable prebuilt Linux CUDA binary is currently available. NVIDIA GPUs use Vulkan. |
| **NVIDIA** | CUDA / Vulkan | Vulkan / CPU | Auto-detects NVIDIA. Prompt-driven CUDA setup downloads prebuilt or compiles from source. Falls back to Vulkan for GTX. |
| **AMD Radeon** | ROCm | Vulkan | ROCm provides best AMD performance when host ROCm drivers are available. |
| **Intel Arc / integrated** | Vulkan | CPU | Cross-vendor Vulkan support. |
| **Intel Core Ultra NPU** | OpenVINO NPU | CPU | Requires the Intel Linux NPU driver, kernel 6.6+, Python 3, and `./linux.sh --setup-openvino`. |
@@ -109,17 +110,16 @@ local-ai-image-generator/
| Hardware | Primary | Fallback | Notes |
| :--- | :--- | :--- | :--- |
| **Apple Silicon (M1 or newer)** | Metal | CPU | Uses the official Darwin arm64 stable-diffusion.cpp backend. |
| **Intel Mac** | Source build required | CPU | Official prebuilt macOS backend is Apple Silicon only. |
**System requirements:**
- **64-bit Windows 10 or Windows 11** is required for the portable Node.js 22 runtime used by the Windows launcher.
- **glibc 2.38 or newer** is required for the prebuilt Linux backends (Ubuntu 24.04, Fedora 40+, etc.).
- The setup script will warn you if your glibc is older. You can still run setup, but the prebuilt backends will not start.
- **Linux OpenVINO NPU:** Intel Core Ultra, x86_64 Linux, kernel 6.6+, a working `/dev/accel/accel0` device, Python 3 with `venv`, and the Intel Linux NPU driver are required.
- **Apple Silicon (M1 or newer)** is required for the prebuilt macOS Metal backend.
- **Apple Silicon (M1 or newer)** is required for the prebuilt macOS Metal backend. *(Note: macOS Intel hardware is completely unsupported and has not been tested.)*
**Linux setup modes:**
- **Default (`./linux.sh`)**: Downloads CPU + Vulkan backends (~120–150 MB).
- **Default (`./linux.sh`)**: Downloads CPU + Vulkan backends (~120–150 MB). If an NVIDIA GPU is detected, prompts to set up CUDA (attempts to download prebuilt, otherwise compiles from source).
- **Maximum Performance (`./linux.sh --max-perf`)**: Also downloads the ROCm backend. Total download ~1.3 GB.
- **Intel NPU (`./linux.sh --setup-openvino`)**: Creates a local OpenVINO Python environment and verifies that the Intel NPU driver exposes an `NPU` device.
@@ -129,11 +129,20 @@ local-ai-image-generator/
Typical generation times for an image with **20 steps** (e.g. 512x512 resolution; actual times can vary depending on specific hardware specifications, clock speeds, and system load):
* **CUDA GPU (Nvidia RTX):** ~10 seconds.
* **ROCm GPU (AMD RDNA2/RDNA3):** ~15–30 seconds.
* **Vulkan GPU (AMD / Intel Arc):** ~89 seconds.
* **GTX Vulkan Fallback (Nvidia GTX):** ~30 seconds (Vulkan runs significantly faster on legacy GTX series cards since they lack Tensor Cores).
* **CPU (Fallback):** ~150 - 300+ seconds (highly dependent on processor core count, speed, and AVX instruction sets).
| Operating System | Backend / Hardware | Typical Time (512x512) | Notes |
| :--- | :--- | :--- | :--- |
| **Windows** | NVIDIA RTX (CUDA) | ~10 seconds | Native CUDA with Tensor Core acceleration. |
| **Windows** | AMD Radeon / Intel Arc (Vulkan) | ~89 seconds | Cross-vendor Vulkan GPU fallback. |
| **Windows** | NVIDIA GTX (Vulkan) | ~30 seconds | Vulkan is faster than CUDA on legacy GTX cards. |
| **Windows** | CPU | 150 - 300+ seconds | Legacy fallback, highly dependent on CPU cores. |
| **Linux** | NVIDIA RTX (CUDA) | ~10 seconds | Automated source-build / prebuilt CUDA. |
| **Linux** | AMD Radeon (ROCm) | ~15 - 30 seconds | Native AMD performance (requires ROCm drivers). |
| **Linux** | NVIDIA GTX (Vulkan) | ~29 seconds | Tested on GTX 1650 (25.5s sampling, 3.7s decode). |
| **Linux** | AMD / Intel Arc (Vulkan) | ~89 seconds | Vulkan API acceleration. |
| **Linux** | Intel Core Ultra (OpenVINO NPU) | ~15 - 40 seconds | Dedicated Intel NPU hardware acceleration. |
| **Linux** | CPU | 150 - 300+ seconds | Logical thread computation. |
| **macOS** | Apple Silicon M-Series (Metal GPU) | ~12 - 25 seconds | Native Metal backend on Apple Silicon. |
| **macOS** | Apple Silicon ANE (Apple NPU) | ~10 - 18 seconds | CoreML compilation on Apple Neural Engine. |
---
@@ -149,7 +158,7 @@ Typical generation times for an image with **20 steps** (e.g. 512x512 resolution
## 🔨 Building Linux Backends From Source
If your distribution has an older glibc than 2.38, or you want a CUDA backend on Linux, you can build `stable-diffusion.cpp` directly on your machine. The resulting binary will be linked against your system's glibc and will not have the compatibility issues of the prebuilt releases.
The setup script (`scripts/setup.sh`) now automates building and setting up the CUDA backend from source when selected. If you want to manually build all backends (CPU, Vulkan, and CUDA) at once, you can run the included `scripts/build_from_source.sh` script.
For macOS, the included `scripts/build_from_source.sh` builds the Metal backend and copies it to `app/backend/mac/sd`.
+52 -7
View File
@@ -53,18 +53,63 @@ if [[ $SETUP_OPENVINO -eq 1 ]]; then
bash "$SCRIPT_DIR/scripts/setup-openvino-npu.sh"
fi
# ── Symlink node_modules to avoid OS conflicts ──────────────────────────────
# ── Setup node_modules to avoid OS conflicts ────────────────────────────────
FRONTEND_NODE_MODULES="$APP_DIR/frontend/node_modules"
LINUX_NODE_MODULES="$APP_DIR/frontend/node_modules_linux"
ACTIVE_OS_FILE="$APP_DIR/frontend/.active_modules_os"
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Migrating existing node_modules to node_modules_linux..."
mv "$FRONTEND_NODE_MODULES" "$LINUX_NODE_MODULES"
# Attempt to create a test symlink to check if filesystem supports symlinks
USE_SYMLINKS=true
TEST_LINK="$APP_DIR/frontend/.test_symlink"
rm -f "$TEST_LINK"
if ln -s "node_modules_linux" "$TEST_LINK" 2>/dev/null; then
rm -f "$TEST_LINK"
else
USE_SYMLINKS=false
fi
rm -f "$FRONTEND_NODE_MODULES"
mkdir -p "$LINUX_NODE_MODULES"
ln -sf "node_modules_linux" "$FRONTEND_NODE_MODULES"
if [ "$USE_SYMLINKS" = true ]; then
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Migrating existing node_modules to node_modules_linux..."
mv "$FRONTEND_NODE_MODULES" "$LINUX_NODE_MODULES"
fi
rm -f "$FRONTEND_NODE_MODULES"
mkdir -p "$LINUX_NODE_MODULES"
ln -sf "node_modules_linux" "$FRONTEND_NODE_MODULES"
else
# Fallback: Filesystem does not support symlinks (e.g. FAT32/exFAT)
echo " >> Filesystem does not support symlinks. Using directory swapping fallback..."
if [[ -L "$FRONTEND_NODE_MODULES" || -f "$FRONTEND_NODE_MODULES" ]]; then
rm -f "$FRONTEND_NODE_MODULES"
fi
PREV_OS=""
if [[ -f "$ACTIVE_OS_FILE" ]]; then
PREV_OS=$(cat "$ACTIVE_OS_FILE")
fi
if [[ -d "$FRONTEND_NODE_MODULES" && "$PREV_OS" != "linux" ]]; then
if [[ -n "$PREV_OS" ]]; then
echo " >> Swapping out node_modules to node_modules_$PREV_OS..."
rm -rf "$APP_DIR/frontend/node_modules_$PREV_OS"
mv "$FRONTEND_NODE_MODULES" "$APP_DIR/frontend/node_modules_$PREV_OS"
else
echo " >> Saving node_modules as node_modules_windows..."
rm -rf "$APP_DIR/frontend/node_modules_windows"
mv "$FRONTEND_NODE_MODULES" "$APP_DIR/frontend/node_modules_windows"
fi
fi
if [[ -d "$LINUX_NODE_MODULES" && ! -d "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Swapping in node_modules_linux..."
mv "$LINUX_NODE_MODULES" "$FRONTEND_NODE_MODULES"
elif [[ ! -d "$FRONTEND_NODE_MODULES" ]]; then
mkdir -p "$FRONTEND_NODE_MODULES"
fi
echo "linux" > "$ACTIVE_OS_FILE"
fi
# ── First-time setup check ─────────────────────────────────────────────────
if [[ ! -d "$NODE_DIR" ]]; then
+52 -7
View File
@@ -28,18 +28,63 @@ FRONTEND_PORT="${FRONTEND_PORT:-1420}"
SETUP_REASON=""
SETUP_MODE="Repair"
# ── Symlink node_modules to avoid OS conflicts ──────────────────────────────
# ── Setup node_modules to avoid OS conflicts ────────────────────────────────
FRONTEND_NODE_MODULES="$APP_DIR/frontend/node_modules"
MAC_NODE_MODULES="$APP_DIR/frontend/node_modules_mac"
ACTIVE_OS_FILE="$APP_DIR/frontend/.active_modules_os"
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Migrating existing node_modules to node_modules_mac..."
mv "$FRONTEND_NODE_MODULES" "$MAC_NODE_MODULES"
# Attempt to create a test symlink to check if filesystem supports symlinks
USE_SYMLINKS=true
TEST_LINK="$APP_DIR/frontend/.test_symlink"
rm -f "$TEST_LINK"
if ln -s "node_modules_mac" "$TEST_LINK" 2>/dev/null; then
rm -f "$TEST_LINK"
else
USE_SYMLINKS=false
fi
rm -f "$FRONTEND_NODE_MODULES"
mkdir -p "$MAC_NODE_MODULES"
ln -sf "node_modules_mac" "$FRONTEND_NODE_MODULES"
if [ "$USE_SYMLINKS" = true ]; then
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Migrating existing node_modules to node_modules_mac..."
mv "$FRONTEND_NODE_MODULES" "$MAC_NODE_MODULES"
fi
rm -f "$FRONTEND_NODE_MODULES"
mkdir -p "$MAC_NODE_MODULES"
ln -sf "node_modules_mac" "$FRONTEND_NODE_MODULES"
else
# Fallback: Filesystem does not support symlinks (e.g. FAT32/exFAT)
echo " >> Filesystem does not support symlinks. Using directory swapping fallback..."
if [[ -L "$FRONTEND_NODE_MODULES" || -f "$FRONTEND_NODE_MODULES" ]]; then
rm -f "$FRONTEND_NODE_MODULES"
fi
PREV_OS=""
if [[ -f "$ACTIVE_OS_FILE" ]]; then
PREV_OS=$(cat "$ACTIVE_OS_FILE")
fi
if [[ -d "$FRONTEND_NODE_MODULES" && "$PREV_OS" != "mac" ]]; then
if [[ -n "$PREV_OS" ]]; then
echo " >> Swapping out node_modules to node_modules_$PREV_OS..."
rm -rf "$APP_DIR/frontend/node_modules_$PREV_OS"
mv "$FRONTEND_NODE_MODULES" "$APP_DIR/frontend/node_modules_$PREV_OS"
else
echo " >> Saving node_modules as node_modules_windows..."
rm -rf "$APP_DIR/frontend/node_modules_windows"
mv "$FRONTEND_NODE_MODULES" "$APP_DIR/frontend/node_modules_windows"
fi
fi
if [[ -d "$MAC_NODE_MODULES" && ! -d "$FRONTEND_NODE_MODULES" ]]; then
echo " >> Swapping in node_modules_mac..."
mv "$MAC_NODE_MODULES" "$FRONTEND_NODE_MODULES"
elif [[ ! -d "$FRONTEND_NODE_MODULES" ]]; then
mkdir -p "$FRONTEND_NODE_MODULES"
fi
echo "mac" > "$ACTIVE_OS_FILE"
fi
# ── First-time setup check ─────────────────────────────────────────────────
if [[ ! -d "$NODE_DIR" ]]; then
+22
View File
@@ -402,14 +402,36 @@ if (-not (Test-Path $npmCmd)) {
# If node_modules is a Unix symlink/junction, remove it so Windows can install natively into a real directory
$nodeModulesDir = Join-Path $frontendDir "node_modules"
$activeOsFile = Join-Path $frontendDir ".active_modules_os"
$prevOs = ""
if (Test-Path $activeOsFile) {
$prevOs = (Get-Content $activeOsFile -Raw).Trim()
}
if (Test-Path $nodeModulesDir) {
$item = Get-Item $nodeModulesDir
if ($item.Attributes -match "ReparsePoint") {
Print-Info "Removing Unix symlink for node_modules on Windows..."
Remove-Item $nodeModulesDir -Force -ErrorAction SilentlyContinue
} elseif ($prevOs -ne "windows" -and $prevOs -ne "") {
# It's a real folder, but it belongs to another OS (e.g. linux or mac)
Print-Info "Swapping out node_modules to node_modules_$prevOs..."
$targetDir = Join-Path $frontendDir "node_modules_$prevOs"
if (Test-Path $targetDir) { Remove-Item $targetDir -Recurse -Force -ErrorAction SilentlyContinue }
Move-Item $nodeModulesDir $targetDir -Force
}
}
# Now swap in node_modules_windows if it exists
$winModulesDir = Join-Path $frontendDir "node_modules_windows"
if ((Test-Path $winModulesDir) -and -not (Test-Path $nodeModulesDir)) {
Print-Info "Swapping in node_modules_windows..."
Move-Item $winModulesDir $nodeModulesDir -Force
}
# Mark windows as active
"windows" | Out-File -FilePath $activeOsFile -NoNewline -Encoding utf8
Push-Location $frontendDir
$oldPath = $env:PATH
try {
+60 -12
View File
@@ -269,7 +269,7 @@ if [[ "$PLATFORM" == "Darwin" ]]; then
print_step 2 $TOTAL_STEPS "Setting up stable-diffusion.cpp Metal backend (app/backend/mac/)"
if [[ "$ARCH" != "arm64" ]]; then
print_fail "The official macOS backend binary is Apple Silicon only (arm64)."
print_info "Intel Macs need a local source build with Metal/OpenBLAS and a matching app/backend/mac/sd binary."
print_info "macOS Intel hardware is completely unsupported and has not been tested."
exit 1
fi
@@ -493,29 +493,77 @@ if [[ ! -x "$NPM_BIN" ]]; then
exit 1
fi
# Ensure correct OS-specific node_modules folder is symlinked to avoid conflicts
# Ensure correct OS-specific node_modules folder is symlinked or swapped to avoid conflicts
FRONTEND_NODE_MODULES="$FRONTEND_DIR/node_modules"
ACTIVE_OS_FILE="$FRONTEND_DIR/.active_modules_os"
if [[ "$PLATFORM" == "Darwin" ]]; then
OS_NODE_MODULES="$FRONTEND_DIR/node_modules_mac"
OS_LABEL="node_modules_mac"
CURRENT_OS="mac"
else
OS_NODE_MODULES="$FRONTEND_DIR/node_modules_linux"
OS_LABEL="node_modules_linux"
CURRENT_OS="linux"
fi
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
print_info "Migrating existing node_modules to $OS_LABEL..."
if [[ -d "$OS_NODE_MODULES" ]]; then
rm -rf "$FRONTEND_NODE_MODULES"
else
mv "$FRONTEND_NODE_MODULES" "$OS_NODE_MODULES"
# Attempt to create a test symlink to check if filesystem supports symlinks
USE_SYMLINKS=true
TEST_LINK="$FRONTEND_DIR/.test_symlink"
rm -f "$TEST_LINK"
if ln -s "$OS_LABEL" "$TEST_LINK" 2>/dev/null; then
rm -f "$TEST_LINK"
else
USE_SYMLINKS=false
fi
if [ "$USE_SYMLINKS" = true ]; then
if [[ -d "$FRONTEND_NODE_MODULES" && ! -L "$FRONTEND_NODE_MODULES" ]]; then
print_info "Migrating existing node_modules to $OS_LABEL..."
if [[ -d "$OS_NODE_MODULES" ]]; then
rm -rf "$FRONTEND_NODE_MODULES"
else
mv "$FRONTEND_NODE_MODULES" "$OS_NODE_MODULES"
fi
fi
rm -rf "$FRONTEND_NODE_MODULES"
mkdir -p "$OS_NODE_MODULES"
ln -sf "$OS_LABEL" "$FRONTEND_NODE_MODULES"
else
# Fallback: Filesystem does not support symlinks (e.g. FAT32/exFAT)
print_info "Filesystem does not support symlinks. Using directory swapping fallback..."
if [[ -L "$FRONTEND_NODE_MODULES" || -f "$FRONTEND_NODE_MODULES" ]]; then
rm -rf "$FRONTEND_NODE_MODULES"
fi
PREV_OS=""
if [[ -f "$ACTIVE_OS_FILE" ]]; then
PREV_OS=$(cat "$ACTIVE_OS_FILE")
fi
if [[ -d "$FRONTEND_NODE_MODULES" && "$PREV_OS" != "$CURRENT_OS" ]]; then
if [[ -n "$PREV_OS" ]]; then
print_info "Swapping out node_modules to node_modules_$PREV_OS..."
rm -rf "$FRONTEND_DIR/node_modules_$PREV_OS"
mv "$FRONTEND_NODE_MODULES" "$FRONTEND_DIR/node_modules_$PREV_OS"
else
print_info "Saving node_modules as node_modules_windows..."
rm -rf "$FRONTEND_DIR/node_modules_windows"
mv "$FRONTEND_NODE_MODULES" "$FRONTEND_DIR/node_modules_windows"
fi
fi
if [[ -d "$OS_NODE_MODULES" && ! -d "$FRONTEND_NODE_MODULES" ]]; then
print_info "Swapping in $OS_LABEL..."
mv "$OS_NODE_MODULES" "$FRONTEND_NODE_MODULES"
elif [[ ! -d "$FRONTEND_NODE_MODULES" ]]; then
mkdir -p "$FRONTEND_NODE_MODULES"
fi
echo "$CURRENT_OS" > "$ACTIVE_OS_FILE"
fi
rm -rf "$FRONTEND_NODE_MODULES"
mkdir -p "$OS_NODE_MODULES"
ln -sf "$OS_LABEL" "$FRONTEND_NODE_MODULES"
cd "$FRONTEND_DIR"
export PATH="$NODE_DIR/bin:$PATH"