From 8c8020ae18918c5fe3e4246311165f69674a8178 Mon Sep 17 00:00:00 2001 From: "INTER.Tech" Date: Thu, 23 Apr 2026 14:39:12 -0400 Subject: [PATCH 1/6] fix(tensorrt): TRT 10.16.1.11 + modelopt install + run_pip quote-fix - tensorrt.py: bump tensorrt_cu12 to 10.16.1.11, polygraphy 0.49.26, onnx-graphsurgeon 0.6.1; add FP8-quant block (modelopt + cupy-cuda12x + numpy re-lock); re-pin onnxruntime-gpu==1.24.4 with --no-deps after modelopt downgrade; drop shell-style quotes inside package specs (run_pip uses subprocess + .split(), quotes become literal arg chars). - installer.py: remove torchaudio from cu128 config (not needed); minor ruff format cleanup. - verifier.py: float32_to_bfloat16 diagnostic points to onnx-gs 0.6.1 instead of suggesting an onnx downgrade. - __init__.py, __main__.py, cli.py: ruff format cleanup (blank lines, unused import, raw docstring). --- sd_installer/__init__.py | 1 + sd_installer/__main__.py | 1 + sd_installer/cli.py | 39 +++++++++++-------- sd_installer/installer.py | 32 ++++++++-------- sd_installer/tensorrt.py | 44 +++++++++++++-------- sd_installer/verifier.py | 81 ++++++++++++++------------------------- 6 files changed, 96 insertions(+), 102 deletions(-) diff --git a/sd_installer/__init__.py b/sd_installer/__init__.py index 6c059c8..0cbabfc 100644 --- a/sd_installer/__init__.py +++ b/sd_installer/__init__.py @@ -16,4 +16,5 @@ from .installer import Installer from .verifier import Verifier + __all__ = ["Installer", "Verifier", "__version__"] diff --git a/sd_installer/__main__.py b/sd_installer/__main__.py index 2a0fbda..e878b7a 100644 --- a/sd_installer/__main__.py +++ b/sd_installer/__main__.py @@ -2,5 +2,6 @@ from .cli import main + if __name__ == "__main__": exit(main()) diff --git a/sd_installer/cli.py b/sd_installer/cli.py index 9834f44..3f7110c 100644 --- a/sd_installer/cli.py +++ b/sd_installer/cli.py @@ -15,13 +15,12 @@ """ import argparse -import os import sys from pathlib import Path def find_base_folder() -> Path: - """ + r""" Find the StreamDiffusion base folder (where setup.py lives). Runtime structure: @@ -47,9 +46,9 @@ def find_base_folder() -> Path: # __file__ = .../StreamDiffusion-installer/sd_installer/cli.py # We want: .../StreamDiffusion/ this_file = Path(__file__).resolve() - sd_installer_pkg = this_file.parent # sd_installer/ - installer_repo = sd_installer_pkg.parent # StreamDiffusion-installer/ - base = installer_repo.parent # StreamDiffusion/ + sd_installer_pkg = this_file.parent # sd_installer/ + installer_repo = sd_installer_pkg.parent # StreamDiffusion-installer/ + base = installer_repo.parent # StreamDiffusion/ if (base / "setup.py").exists(): return base @@ -85,7 +84,7 @@ def cmd_check(args): if venv_path.exists(): print(f"Venv: Found at {venv_path}") else: - print(f"Venv: Not found (will be created during install)") + print("Venv: Not found (will be created during install)") # Check StreamDiffusion setup.py (base folder IS StreamDiffusion) setup_py = base / "setup.py" @@ -197,7 +196,7 @@ def cmd_diagnose(args): print(f" [{status}] {check['name']}") if check["error"]: # Print just the last line of the error - error_line = check["error"].split('\n')[-1][:60] + error_line = check["error"].split("\n")[-1][:60] print(f" {error_line}") return 0 @@ -205,7 +204,7 @@ def cmd_diagnose(args): def cmd_repair(args): """Auto-fix known issues.""" - from .verifier import Verifier, KNOWN_ERRORS + from .verifier import Verifier try: base = Path(args.base_folder) if args.base_folder else find_base_folder() @@ -236,6 +235,7 @@ def cmd_repair(args): for check in info["checks"]: if not check["passed"] and check["error"]: from .verifier import match_known_error + fix = match_known_error(check["error"]) if fix: fixes_needed.append((check["name"], fix)) @@ -245,10 +245,15 @@ def cmd_repair(args): # numpy 2.x numpy_ver = info["versions"].get("numpy", "") if numpy_ver.startswith("2."): - fixes_needed.append(("numpy version", { - "cause": f"numpy {numpy_ver} detected (2.x breaks things)", - "fix": "pip install numpy==1.26.4 --force-reinstall" - })) + fixes_needed.append( + ( + "numpy version", + { + "cause": f"numpy {numpy_ver} detected (2.x breaks things)", + "fix": "pip install numpy==1.26.4 --force-reinstall", + }, + ) + ) if not fixes_needed: print("No known issues detected that can be auto-fixed.") @@ -264,18 +269,19 @@ def cmd_repair(args): if not args.yes: response = input("Apply fixes? [y/N]: ") - if response.lower() != 'y': + if response.lower() != "y": print("Aborted.") return 0 # Apply fixes import subprocess + for name, fix in fixes_needed: print(f"Applying fix for {name}...") cmd = [str(python_exe), "-m", "pip"] + fix["fix"].replace("pip ", "").split() result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode == 0: - print(f" OK") + print(" OK") else: print(f" FAILED: {result.stderr}") @@ -314,7 +320,7 @@ def cmd_generate_bat(args): def cmd_install_tensorrt(args): """Install TensorRT packages.""" - from .tensorrt import install, get_cuda_version_from_torch + from .tensorrt import get_cuda_version_from_torch, install print("StreamDiffusionTD TensorRT Installation") print("=" * 40) @@ -381,7 +387,8 @@ def main(): # repair command repair_parser = subparsers.add_parser("repair", help="Auto-fix known issues") repair_parser.add_argument( - "-y", "--yes", + "-y", + "--yes", action="store_true", help="Apply fixes without prompting", ) diff --git a/sd_installer/installer.py b/sd_installer/installer.py index 11214f0..d982d87 100644 --- a/sd_installer/installer.py +++ b/sd_installer/installer.py @@ -11,12 +11,11 @@ 5. Verify imports - Catch failures immediately """ -import os -import sys import subprocess -import shutil +import sys from pathlib import Path -from typing import Optional, Callable +from typing import Callable, Optional + # Version pins - packages NOT in setup.py that must be manually pinned MANUAL_PINS = { @@ -65,7 +64,7 @@ "cu128": { "torch": "2.7.0", "torchvision": "0.22.0", - "torchaudio": "2.7.0", + "torchaudio": None, "index_url": "https://download.pytorch.org/whl/cu128", "cuda_python": "12.9.0", "xformers": None, # Not needed - PyTorch 2.7+ has native SDPA @@ -103,10 +102,7 @@ def __init__( # Validate CUDA version if cuda_version not in PYTORCH_CONFIGS: - raise ValueError( - f"Unsupported CUDA version: {cuda_version}. " - f"Supported: {list(PYTORCH_CONFIGS.keys())}" - ) + raise ValueError(f"Unsupported CUDA version: {cuda_version}. Supported: {list(PYTORCH_CONFIGS.keys())}") self.pytorch_config = PYTORCH_CONFIGS[cuda_version] @@ -238,7 +234,7 @@ def phase3b_insightface(self): version_str = result.stdout.strip() try: - major, minor = map(int, version_str.split('.')) + major, minor = map(int, version_str.split(".")) py_version = (major, minor) except ValueError: print(f" WARNING: Could not parse Python version '{version_str}', skipping insightface pre-install") @@ -269,10 +265,13 @@ def phase5_missing_pins(self): # Force reinstall varshith15 diffusers (other deps may have overwritten it) self._report_progress("Ensuring varshith15 diffusers fork with kvo_cache support...", 5, 8) - self._run_pip([ - "--force-reinstall", "--no-deps", - "diffusers @ git+https://github.com/varshith15/diffusers.git@3e3b72f557e91546894340edabc845e894f00922" - ]) + self._run_pip( + [ + "--force-reinstall", + "--no-deps", + "diffusers @ git+https://github.com/varshith15/diffusers.git@3e3b72f557e91546894340edabc845e894f00922", + ] + ) def phase6_conflict_prone(self): """Phase 6: Fix conflict-prone packages with --no-deps.""" @@ -280,8 +279,7 @@ def phase6_conflict_prone(self): # Remove conflicting opencv variants subprocess.run( - [str(self.python_exe), "-m", "pip", "uninstall", "-y", - "opencv-python-headless", "opencv-contrib-python"], + [str(self.python_exe), "-m", "pip", "uninstall", "-y", "opencv-python-headless", "opencv-contrib-python"], capture_output=True, ) @@ -386,7 +384,7 @@ def generate_batch_file(self, output_path: Optional[str] = None, python_exe: Opt pause ''' - with open(output_path, 'w', encoding='utf-8') as f: + with open(output_path, "w", encoding="utf-8") as f: f.write(content) print(f"Generated batch file: {output_path}") diff --git a/sd_installer/tensorrt.py b/sd_installer/tensorrt.py index d4b46e1..a048f67 100644 --- a/sd_installer/tensorrt.py +++ b/sd_installer/tensorrt.py @@ -3,9 +3,10 @@ Standalone module that doesn't rely on streamdiffusion package imports. """ + +import platform import subprocess import sys -import platform from typing import Optional @@ -17,7 +18,7 @@ def run_pip(command: str): def is_installed(package_name: str) -> bool: """Check if a package is installed""" try: - __import__(package_name.replace('-', '_')) + __import__(package_name.replace("-", "_")) return True except ImportError: return False @@ -27,6 +28,7 @@ def version(package_name: str) -> Optional[str]: """Get version of installed package""" try: import importlib.metadata + return importlib.metadata.version(package_name) except Exception: return None @@ -74,6 +76,7 @@ def install(cu: Optional[str] = None): if current_version_str: try: from packaging.version import Version + current_version = Version(current_version_str) if current_version < Version("10.8.0"): print("Uninstalling old TensorRT version...") @@ -84,9 +87,11 @@ def install(cu: Optional[str] = None): print("Uninstalling old TensorRT version...") run_pip("uninstall -y tensorrt") - # For CUDA 12.8+ (RTX 5090/Blackwell support), use TensorRT 10.12+ + # For CUDA 12.8+ (RTX 5090/Blackwell support), use TensorRT 10.16+ + # 10.16.1.11 is the first Blackwell-Windows-production release and fixes + # the 78% FP8 perf regression that shipped in 10.12–10.13 on SM_120. if cuda_version_float >= 12.8: - print("Installing TensorRT 10.12+ for CUDA 12.8+ (Blackwell GPU support)...") + print("Installing TensorRT 10.16+ for CUDA 12.8+ (Blackwell GPU support)...") # Install cuDNN 9 for CUDA 12 cudnn_name = "nvidia-cudnn-cu12==9.7.1.26" @@ -96,7 +101,7 @@ def install(cu: Optional[str] = None): # tensorrt_cu12 is the CUDA 12 wrapper that owns tensorrt/__init__.py # and depends on tensorrt_cu12_libs + tensorrt_cu12_bindings. # All three are normal wheels with Requires-Dist (no pip-inside-pip). - trt_version = "10.12.0.36" + trt_version = "10.16.1.11" print(f"Installing TensorRT {trt_version} for CUDA {cu}...") run_pip(f"install --extra-index-url https://pypi.nvidia.com tensorrt_cu12=={trt_version} --no-cache-dir") @@ -111,7 +116,7 @@ def install(cu: Optional[str] = None): # tensorrt_cu12 is the CUDA 12 wrapper that owns tensorrt/__init__.py # and depends on tensorrt_cu12_libs + tensorrt_cu12_bindings. # All three are normal wheels with Requires-Dist (no pip-inside-pip). - trt_version = "10.12.0.36" + trt_version = "10.16.1.11" print(f"Installing TensorRT {trt_version} for CUDA {cu}...") run_pip(f"install --extra-index-url https://pypi.nvidia.com tensorrt_cu12=={trt_version} --no-cache-dir") @@ -126,9 +131,7 @@ def install(cu: Optional[str] = None): # Install TensorRT for CUDA 11 tensorrt_version = "tensorrt==9.0.1.post11.dev4" print(f"Installing TensorRT for CUDA {cu}: {tensorrt_version}") - run_pip( - f"install --extra-index-url https://pypi.nvidia.com {tensorrt_version} --no-cache-dir" - ) + run_pip(f"install --extra-index-url https://pypi.nvidia.com {tensorrt_version} --no-cache-dir") else: print(f"Unsupported CUDA version: {cu}") print("Supported versions: CUDA 11.x, 12.x, 12.8+") @@ -137,18 +140,25 @@ def install(cu: Optional[str] = None): # Install additional TensorRT tools if not is_installed("polygraphy"): print("Installing polygraphy...") - run_pip( - "install polygraphy==0.49.24 --extra-index-url https://pypi.ngc.nvidia.com --no-cache-dir" - ) + run_pip("install polygraphy==0.49.26 --extra-index-url https://pypi.ngc.nvidia.com --no-cache-dir") if not is_installed("onnx_graphsurgeon"): print("Installing onnx-graphsurgeon...") - run_pip( - "install onnx-graphsurgeon==0.5.8 --extra-index-url https://pypi.ngc.nvidia.com --no-cache-dir" - ) - if platform.system() == 'Windows' and not is_installed("pywin32"): + run_pip("install onnx-graphsurgeon==0.6.1 --extra-index-url https://pypi.ngc.nvidia.com --no-cache-dir") + + # FP8 quantization dependencies (CUDA 12 only). + # Previously missing — caused ImportError in fp8_quantize.py when users enabled FP8. + # Aligns with FLUX pyproject.toml (nvidia-modelopt >= 0.19.0). + if cuda_major == "12": + print("Installing FP8 quantization dependencies (modelopt, cupy)...") + run_pip("install nvidia-modelopt[onnx]>=0.19.0 cupy-cuda12x==13.6.0 numpy==1.26.4 --no-cache-dir") + # modelopt's resolver downgrades onnxruntime-gpu to 1.22.0; re-assert 1.24.4. + # --no-deps avoids triggering a conflicting re-solve. + run_pip("install onnxruntime-gpu==1.24.4 --no-deps --no-cache-dir") + + if platform.system() == "Windows" and not is_installed("pywin32"): print("Installing pywin32...") run_pip("install pywin32==306 --no-cache-dir") - if platform.system() == 'Windows' and not is_installed("triton"): + if platform.system() == "Windows" and not is_installed("triton"): print("Installing triton-windows...") run_pip("install triton-windows==3.4.0.post21 --no-cache-dir") diff --git a/sd_installer/verifier.py b/sd_installer/verifier.py index 2cc484c..fa23d60 100644 --- a/sd_installer/verifier.py +++ b/sd_installer/verifier.py @@ -12,6 +12,7 @@ @dataclass class VerificationResult: """Result of a single verification check.""" + name: str passed: bool message: str @@ -23,67 +24,39 @@ class VerificationResult: ( "torch CUDA", "import torch; assert torch.cuda.is_available(), 'CUDA not available'; print(f'{torch.__version__}+cu{torch.version.cuda} | {torch.cuda.get_device_name(0)}')", - "PyTorch with CUDA" - ), - ( - "StreamDiffusion", - "from streamdiffusion.config import load_config; print('OK')", - "StreamDiffusion core" - ), - ( - "timm RotaryEmbedding", - "from timm.layers import RotaryEmbedding; print('OK')", - "timm (>=1.0.24 required)" - ), - ( - "mediapipe", - "import mediapipe as mp; mp.solutions.drawing_utils; print('OK')", - "mediapipe solutions" - ), - ( - "transformers MT5", - "from transformers import MT5Tokenizer; print('OK')", - "transformers (MT5Tokenizer)" - ), - ( - "huggingface_hub", - "from huggingface_hub import hf_hub_download; print('OK')", - "huggingface_hub" + "PyTorch with CUDA", ), + ("StreamDiffusion", "from streamdiffusion.config import load_config; print('OK')", "StreamDiffusion core"), + ("timm RotaryEmbedding", "from timm.layers import RotaryEmbedding; print('OK')", "timm (>=1.0.24 required)"), + ("mediapipe", "import mediapipe as mp; mp.solutions.drawing_utils; print('OK')", "mediapipe solutions"), + ("transformers MT5", "from transformers import MT5Tokenizer; print('OK')", "transformers (MT5Tokenizer)"), + ("huggingface_hub", "from huggingface_hub import hf_hub_download; print('OK')", "huggingface_hub"), ( "numpy version", "import numpy; v = numpy.__version__; assert v.startswith('1.'), f'numpy 2.x detected: {v}'; print(v)", - "numpy (<2.0.0 required)" + "numpy (<2.0.0 required)", ), ( "diffusers fork", "import inspect; from diffusers.models.attention_processor import Attention; assert 'kvo_cache' in inspect.signature(Attention.forward).parameters, 'Missing kvo_cache'; print('OK')", - "diffusers (varshith15 fork with kvo_cache)" - ), - ( - "accelerate", - "from accelerate import Accelerator; print('OK')", - "accelerate" - ), - ( - "controlnet_aux", - "from controlnet_aux import OpenposeDetector; print('OK')", - "controlnet_aux" + "diffusers (varshith15 fork with kvo_cache)", ), + ("accelerate", "from accelerate import Accelerator; print('OK')", "accelerate"), + ("controlnet_aux", "from controlnet_aux import OpenposeDetector; print('OK')", "controlnet_aux"), ( "peft (USE_PEFT_BACKEND)", "from diffusers.utils import USE_PEFT_BACKEND; assert USE_PEFT_BACKEND, 'peft not detected'; print('OK')", - "peft (required for Cached Attention/StreamV2V)" + "peft (required for Cached Attention/StreamV2V)", ), ( "protobuf version", "import google.protobuf; v = google.protobuf.__version__; major = int(v.split('.')[0]); assert major < 5, f'protobuf {v} (>=5.x breaks TRT engine builds)'; print(v)", - "protobuf (<5.0 required for TRT)" + "protobuf (<5.0 required for TRT)", ), ( "onnx version", "import onnx; v = onnx.__version__; parts = [int(x) for x in v.split('.')[:2]]; assert parts[0] == 1 and parts[1] < 20, f'onnx {v} (>=1.20 removes float32_to_bfloat16)'; print(v)", - "onnx (<1.20 required for TRT)" + "onnx (<1.20 required for TRT)", ), ] @@ -178,7 +151,7 @@ def run_all(self, verbose: bool = True) -> bool: print(f"FAIL: {result.message}") if result.error: # Print first line of error - error_line = result.error.split('\n')[-1] + error_line = result.error.split("\n")[-1] print(f" {error_line}") if verbose: @@ -211,10 +184,12 @@ def diagnose(self) -> dict: try: result = subprocess.run( [self.python_exe, "-c", gpu_code], - capture_output=True, text=True, timeout=30, + capture_output=True, + text=True, + timeout=30, ) if result.returncode == 0: - lines = result.stdout.strip().split('\n') + lines = result.stdout.strip().split("\n") info["gpu"]["name"] = lines[0] info["gpu"]["vram_mb"] = int(lines[1]) info["gpu"]["compute_capability"] = lines[2] @@ -224,12 +199,14 @@ def diagnose(self) -> dict: # Run all checks and collect detailed info for name, code, description in VERIFICATION_CHECKS: result = self.check(name, code, description) - info["checks"].append({ - "name": name, - "passed": result.passed, - "message": result.message, - "error": result.error, - }) + info["checks"].append( + { + "name": name, + "passed": result.passed, + "message": result.message, + "error": result.error, + } + ) # Get version information for key packages version_checks = [ @@ -290,8 +267,8 @@ def diagnose(self) -> dict: "fix": "pip install accelerate==1.10.0", }, "'onnx.helper' has no attribute 'float32_to_bfloat16'": { - "cause": "onnx version too new", - "fix": "pip install onnx==1.18.0", + "cause": "onnx-graphsurgeon too old for onnx>=1.19 (float32_to_bfloat16 was removed)", + "fix": "pip install onnx-graphsurgeon==0.6.1 --extra-index-url https://pypi.ngc.nvidia.com", }, "Missing kvo_cache": { "cause": "Wrong diffusers installed (vanilla instead of varshith15 fork)", From 4b23a5688de3fa6aacf10c59bb55d02ce8503c0d Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 23 May 2026 21:03:10 -0400 Subject: [PATCH 2/6] chore(deps): add security floor pins for idna, Mako, urllib3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes 6 CVEs patched in deps audit 2026-05-23: - idna >=3.16 (CVE-2026-45409: punycode resource exhaustion) - Mako >=1.3.12 (CVE-2026-44307: Windows backslash path traversal) - urllib3 >=2.7.0 (CVE-2026-44432/44431: over-decompression, cross-origin redirect) Added to MANUAL_PINS and installed in phase7_numpy_lock so upgrade runs on both fresh and existing installs. Fresh pip resolves already satisfy these floors; this ensures the minimum on partial updates. pip and onnxruntime-gpu CVEs are handled separately: - pip: phase1_foundation already runs --upgrade pip (gets latest) - onnx 1.19.1: 6 CVEs deferred — 1.21.0 breaks FP8 quantization Co-Authored-By: Claude Opus 4.7 --- sd_installer/installer.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sd_installer/installer.py b/sd_installer/installer.py index d982d87..a61b2fa 100644 --- a/sd_installer/installer.py +++ b/sd_installer/installer.py @@ -25,6 +25,10 @@ "python-osc": "", # Required for TouchDesigner OSC communication "peft": "0.17.1", # Required for Cached Attention (StreamV2V) - enables USE_PEFT_BACKEND "protobuf": "4.25.8", # Required by mediapipe, onnx/TensorRT - protobuf 6.x breaks serialization, setup.py requires >=4.25.8 + # Security floor pins (transitive deps — pip resolves these on fresh install, but floor ensures upgrade on update) + "idna": ">=3.16", # CVE-2026-45409: punycode resource exhaustion + "Mako": ">=1.3.12", # CVE-2026-44307: Windows backslash path traversal + "urllib3": ">=2.7.0", # CVE-2026-44432/44431: response over-decompression; cross-origin redirect } # Pre-built insightface wheels for Windows (PyPI has no Windows wheels, requires C++ build tools) @@ -287,13 +291,20 @@ def phase6_conflict_prone(self): self._run_pip(["--no-deps", f"opencv-python=={MANUAL_PINS['opencv-python']}"]) def phase7_numpy_lock(self): - """Phase 7: Final numpy and protobuf lock (other packages may have upgraded them).""" + """Phase 7: Final numpy/protobuf lock + security floor pins.""" self._report_progress(f"Final numpy lock (numpy=={MANUAL_PINS['numpy']})...", 7, 8) self._run_pip([f"numpy=={MANUAL_PINS['numpy']}", "--force-reinstall"]) self._report_progress(f"Final protobuf lock (protobuf=={MANUAL_PINS['protobuf']})...", 7, 8) self._run_pip([f"protobuf=={MANUAL_PINS['protobuf']}", "--force-reinstall"]) + self._report_progress("Applying security floor pins (idna, Mako, urllib3)...", 7, 8) + self._run_pip([ + f"idna{MANUAL_PINS['idna']}", + f"Mako{MANUAL_PINS['Mako']}", + f"urllib3{MANUAL_PINS['urllib3']}", + ]) + def phase8_verify(self) -> bool: """Phase 8: Verify installation with import tests.""" from .verifier import Verifier From d60be9a6dbc82a7df2d705c7dcc05687556db80c Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 8 Jul 2026 12:07:57 -0400 Subject: [PATCH 3/6] fix(installer): install cuda-link 1.12.0 wheel + pywin32 311 + bump v0.3.2 cuda-link (CUDA-IPC zero-copy transport) was never installed on a clean install: setup.py only exposes it via the optional cuda_ipc extra (a git ref to a compiled cp311 extension), which installer.py's phase4 never requests to avoid forcing an MSVC/nvcc source build. Add phase4b_cuda_link, mirroring phase3b_insightface's Python-version-gated prebuilt-wheel install (--no-deps, non-fatal fallback to the mirror-DAT transport). Also fixes pywin32 306->311 in tensorrt.py to match setup.py's authoritative pin (8c8020a fixed every other TensorRT pin but missed this one). Co-Authored-By: Claude Opus 4.8 --- sd_installer/installer.py | 41 +++++++++++++++++++++++++++++++++++++-- sd_installer/tensorrt.py | 2 +- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/sd_installer/installer.py b/sd_installer/installer.py index a61b2fa..3481a98 100644 --- a/sd_installer/installer.py +++ b/sd_installer/installer.py @@ -39,6 +39,14 @@ (3, 12): "https://github.com/Gourieff/Assets/raw/main/Insightface/insightface-0.7.3-cp312-cp312-win_amd64.whl", } +# Pre-built cuda-link wheel (CUDA-IPC zero-copy transport). setup.py's cuda-link pin lives only in +# the optional cuda_ipc extra as a git ref (compiled cp311 extension) — installing that extra would +# force an MSVC/nvcc source build. Install the prebuilt wheel directly instead, --no-deps, so this +# extra is never triggered. Only a cp311 wheel is published. +CUDA_LINK_WHEELS = { + (3, 11): "https://github.com/forkni/cuda-link/releases/download/v1.12.0/cuda_link-1.12.0-cp311-cp311-win_amd64.whl", +} + # PyTorch configurations by CUDA version PYTORCH_CONFIGS = { "cu118": { @@ -260,6 +268,34 @@ def phase4_streamdiffusion(self): # The -e flag makes it editable, setup.py handles all pinned versions self._run_pip(["-e", ".[tensorrt,controlnet,ipadapter]"], check=True, cwd=self.streamdiffusion_path) + def phase4b_cuda_link(self): + """Phase 4b: Install cuda-link from pre-built wheel (CUDA-IPC zero-copy transport). + + Not covered by any setup.py extra actually installed above (cuda_ipc is intentionally + skipped to avoid a source build) — install the compiled wheel directly. Non-fatal: if no + wheel exists for this venv's Python, CUDA-IPC falls back to the mirror-DAT transport. + """ + result = self._run_python("import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") + if result.returncode != 0: + print(" WARNING: Could not detect venv Python version, skipping cuda-link pre-install") + return + + version_str = result.stdout.strip() + try: + major, minor = map(int, version_str.split(".")) + py_version = (major, minor) + except ValueError: + print(f" WARNING: Could not parse Python version '{version_str}', skipping cuda-link pre-install") + return + + wheel_url = CUDA_LINK_WHEELS.get(py_version) + if wheel_url: + self._report_progress(f"Installing cuda-link 1.12.0 from pre-built wheel (Python {version_str})...", 4, 8) + self._run_pip(["--no-deps", wheel_url], check=False) + else: + print(f" WARNING: No pre-built cuda-link wheel for Python {version_str}") + print(" CUDA-IPC zero-copy export will fall back to the mirror-DAT transport") + def phase5_missing_pins(self): """Phase 5: Install packages not pinned in setup.py and fix diffusers.""" self._report_progress("Installing packages not in setup.py (timm, python-osc, peft)...", 5, 8) @@ -324,7 +360,7 @@ def install(self, python_exe: Optional[str] = None) -> bool: True if installation and verification succeeded. """ print("=" * 50) - print(" StreamDiffusionTD v0.3.1 Installation") + print(" StreamDiffusionTD v0.3.2 Installation") print(" Daydream Fork with StreamV2V") print("=" * 50) print() @@ -341,6 +377,7 @@ def install(self, python_exe: Optional[str] = None) -> bool: self.phase3_xformers() self.phase3b_insightface() # Pre-install insightface from wheel (Windows) self.phase4_streamdiffusion() + self.phase4b_cuda_link() # Pre-install cuda-link from wheel (CUDA-IPC transport) self.phase5_missing_pins() self.phase6_conflict_prone() self.phase7_numpy_lock() @@ -383,7 +420,7 @@ def generate_batch_file(self, output_path: Optional[str] = None, python_exe: Opt content = f'''@echo off echo ======================================== -echo StreamDiffusionTD v0.3.1 Installation +echo StreamDiffusionTD v0.3.2 Installation echo Daydream Fork with StreamV2V echo ======================================== diff --git a/sd_installer/tensorrt.py b/sd_installer/tensorrt.py index a048f67..d46530d 100644 --- a/sd_installer/tensorrt.py +++ b/sd_installer/tensorrt.py @@ -157,7 +157,7 @@ def install(cu: Optional[str] = None): if platform.system() == "Windows" and not is_installed("pywin32"): print("Installing pywin32...") - run_pip("install pywin32==306 --no-cache-dir") + run_pip("install pywin32==311 --no-cache-dir") if platform.system() == "Windows" and not is_installed("triton"): print("Installing triton-windows...") run_pip("install triton-windows==3.4.0.post21 --no-cache-dir") From b1712e8329dea28365408595d1d43c9b5751c27f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 8 Jul 2026 12:19:37 -0400 Subject: [PATCH 4/6] fix(installer): bump torch to 2.8.0+cu128 (matches repo's proven target) PYTORCH_CONFIGS["cu128"] pinned torch 2.7.0 / torchvision 0.22.0, but setup.py doesn't constrain torch at all -- this dict was the sole source of truth, and the repo's own README, PKG-INFO, and tests/quality/manifest.json all target torch 2.8.0+cu128 / torchvision 0.23.0 (the golden-image regression harness aborts on any divergence). Bump to match, pairing correctly with the already maintained tensorrt_cu12==10.16.1.11. --- sd_installer/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sd_installer/installer.py b/sd_installer/installer.py index 3481a98..6cb0452 100644 --- a/sd_installer/installer.py +++ b/sd_installer/installer.py @@ -74,8 +74,8 @@ "xformers": None, # Skip - causes conflicts }, "cu128": { - "torch": "2.7.0", - "torchvision": "0.22.0", + "torch": "2.8.0", + "torchvision": "0.23.0", "torchaudio": None, "index_url": "https://download.pytorch.org/whl/cu128", "cuda_python": "12.9.0", From a61e225bd8a8d277d8af7d46c93f5c71edb712ab Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 8 Jul 2026 12:52:17 -0400 Subject: [PATCH 5/6] fix(tensorrt): pin modelopt 0.43.0 + re-assert onnx 1.19.1 in FP8 block Unbounded nvidia-modelopt[onnx]>=0.19.0 floats to 0.45.0, whose [onnx] extra force-upgrades onnx past the immovable setup.py pin (1.19.1), breaking FP8 quant (negative QDQ scale on external-data loading). Confirmed live: a fresh Step 3 install left onnx 1.21.0 / modelopt 0.45.0 in the venv. Pin modelopt to the proven 0.43.0 (matches tests/quality/manifest.json) and re-assert onnx==1.19.1 alongside the existing onnxruntime-gpu re-assert. --- sd_installer/tensorrt.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sd_installer/tensorrt.py b/sd_installer/tensorrt.py index d46530d..8e885b6 100644 --- a/sd_installer/tensorrt.py +++ b/sd_installer/tensorrt.py @@ -147,13 +147,15 @@ def install(cu: Optional[str] = None): # FP8 quantization dependencies (CUDA 12 only). # Previously missing — caused ImportError in fp8_quantize.py when users enabled FP8. - # Aligns with FLUX pyproject.toml (nvidia-modelopt >= 0.19.0). + # modelopt is pinned to 0.43.0 (the proven pin in tests/quality/manifest.json); an unbounded + # ">=0.19.0" spec floats to 0.45.0, whose [onnx] extra force-upgrades onnx to 1.21.0, which + # breaks FP8 quant (external-data loading -> negative QDQ scale). setup.py pins onnx==1.19.1. if cuda_major == "12": print("Installing FP8 quantization dependencies (modelopt, cupy)...") - run_pip("install nvidia-modelopt[onnx]>=0.19.0 cupy-cuda12x==13.6.0 numpy==1.26.4 --no-cache-dir") - # modelopt's resolver downgrades onnxruntime-gpu to 1.22.0; re-assert 1.24.4. - # --no-deps avoids triggering a conflicting re-solve. - run_pip("install onnxruntime-gpu==1.24.4 --no-deps --no-cache-dir") + run_pip("install nvidia-modelopt[onnx]==0.43.0 cupy-cuda12x==13.6.0 numpy==1.26.4 --no-cache-dir") + # Re-assert the setup.py-authoritative pins the modelopt resolver perturbs: it downgrades + # onnxruntime-gpu to 1.22.0 and upgrades onnx past 1.19.1. --no-deps avoids a re-solve. + run_pip("install onnx==1.19.1 onnxruntime-gpu==1.24.4 --no-deps --no-cache-dir") if platform.system() == "Windows" and not is_installed("pywin32"): print("Installing pywin32...") From bb9c8d4a9e796bce1cf4b1500e3b07d0c61601ec Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 12 Jul 2026 16:11:00 -0400 Subject: [PATCH 6/6] feat: auto-persist CUDALINK_LIB_PATH + bump cuda-link wheel to 1.12.1 Add Installer.phase4c_cuda_link_env(): after the cuda-link wheel is installed, persist CUDALINK_LIB_PATH to the user environment via setx (Windows-only, non-fatal) so TouchDesigner library mode resolves the venv site-packages with no manual env-var step. Wired into install() right after phase4b_cuda_link(). Bump the wheel URL and phase progress string from 1.12.0 to 1.12.1. Co-Authored-By: Claude Sonnet 5 --- sd_installer/installer.py | 40 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/sd_installer/installer.py b/sd_installer/installer.py index 6cb0452..d62b5e0 100644 --- a/sd_installer/installer.py +++ b/sd_installer/installer.py @@ -44,7 +44,7 @@ # force an MSVC/nvcc source build. Install the prebuilt wheel directly instead, --no-deps, so this # extra is never triggered. Only a cp311 wheel is published. CUDA_LINK_WHEELS = { - (3, 11): "https://github.com/forkni/cuda-link/releases/download/v1.12.0/cuda_link-1.12.0-cp311-cp311-win_amd64.whl", + (3, 11): "https://github.com/forkni/cuda-link/releases/download/v1.12.1/cuda_link-1.12.1-cp311-cp311-win_amd64.whl", } # PyTorch configurations by CUDA version @@ -290,12 +290,47 @@ def phase4b_cuda_link(self): wheel_url = CUDA_LINK_WHEELS.get(py_version) if wheel_url: - self._report_progress(f"Installing cuda-link 1.12.0 from pre-built wheel (Python {version_str})...", 4, 8) + self._report_progress(f"Installing cuda-link 1.12.1 from pre-built wheel (Python {version_str})...", 4, 8) self._run_pip(["--no-deps", wheel_url], check=False) else: print(f" WARNING: No pre-built cuda-link wheel for Python {version_str}") print(" CUDA-IPC zero-copy export will fall back to the mirror-DAT transport") + def phase4c_cuda_link_env(self): + """Phase 4c: Persist CUDALINK_LIB_PATH -> this venv's site-packages (Windows only). + + TouchDesigner's CUDALinkBootstrap.py reads CUDALINK_LIB_PATH at Text DAT import time to + enable "library mode" (sys.path injection of the installed cuda_link package, aliasing the + 14 mirror DAT names). Persisting it here via `setx` means every TD process launched after + this install inherits it automatically -- no manual env-var step. + + setx writes to HKCU\\Environment (user scope) and only affects processes started + *after* it runs, so TD must be (re)started after installation to pick it up. This + intentionally overwrites any prior manual value (e.g. an older cuda_link_lib\\ target). + Non-fatal: if setx fails or this isn't Windows, TD simply falls back to the mirror-DAT + classic mode. + """ + if sys.platform != "win32": + return # setx is a Windows-only mechanism; non-Windows TD launches are unaffected + + result = self._run_python("import sysconfig; print(sysconfig.get_paths()['purelib'])") + if result.returncode != 0 or not result.stdout.strip(): + print(" WARNING: Could not resolve venv site-packages path, skipping CUDALINK_LIB_PATH setup") + return + + site_packages = result.stdout.strip() + self._report_progress(f"Persisting CUDALINK_LIB_PATH -> {site_packages}", 4, 8) + setx_result = subprocess.run( + ["setx", "CUDALINK_LIB_PATH", site_packages], + capture_output=True, + text=True, + ) + if setx_result.returncode != 0: + print(f" WARNING: setx failed to persist CUDALINK_LIB_PATH: {setx_result.stderr.strip()}") + else: + print(" CUDALINK_LIB_PATH persisted for this user account.") + print(" Restart TouchDesigner (and any open shells) to pick up the new environment variable.") + def phase5_missing_pins(self): """Phase 5: Install packages not pinned in setup.py and fix diffusers.""" self._report_progress("Installing packages not in setup.py (timm, python-osc, peft)...", 5, 8) @@ -378,6 +413,7 @@ def install(self, python_exe: Optional[str] = None) -> bool: self.phase3b_insightface() # Pre-install insightface from wheel (Windows) self.phase4_streamdiffusion() self.phase4b_cuda_link() # Pre-install cuda-link from wheel (CUDA-IPC transport) + self.phase4c_cuda_link_env() # Persist CUDALINK_LIB_PATH -> venv (TD library mode) self.phase5_missing_pins() self.phase6_conflict_prone() self.phase7_numpy_lock()