diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ab8d95e..32b962033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to Stability Matrix will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html). +## v2.15.5 +### Added +- Added new package - [Wan2GP](https://github.com/deepbeepmeep/Wan2GP) +- Added [Stable Diffusion WebUI Forge - Neo](https://github.com/Haoming02/sd-webui-forge-classic/tree/neo) as a separate package for convenience +- Added Tiled VAE decoding as an Inference addon thanks to @NeuralFault! +- Added togglable `--uv` argument to the SD.Next launch options +### Changed +- Moved the original Stable Diffusion WebUI Forge to the "Legacy" packages tab due to inactivity +- Updated to cu130 torch index for ComfyUI installs with Nvidia GPUs +- Consolidated and fixed AMD GPU architecture detection +- Updated SageAttention installer to latest v2.2.0-windows.post4 version +- Updated torch index for Forge-based UIs to rocm6.4 / cu128 depending on GPU - thanks to @NeuralFault! +### Fixed +- Fixed [#1450](https://github.com/LykosAI/StabilityMatrix/issues/1450) - Older SD.Next not launching due to forced `--uv` argument +- Fixed duplicate custom node installations when installing workflows from the Workflow Browser - thanks again to @NeuralFault! +#### 🌟 Visionaries +To our incredible Visionaries: **Waterclouds**, **JungleDragon**, **bluepopsicle**, **Bob S**, and **whudunit**! Your generosity drives this project forward and helps us turn ideas into reality. Thank you for being such a vital part of Stability Matrix! +#### 🚀 Pioneers +A massive thank you to our Pioneer crew! Your support keeps the lights on and the updates flowing. Shoutout to: **Szir777**, **Noah M**, **[USA]TechDude**, **Thom**, **SeraphOfSalem**, **Desert Viber**, **Adam**, **Droolguy**, **ACTUALLY_the_Real_Willem_Dafoe**, **takyamtom**, **robek**, **Phil R**, **Tundra Everquill**, **TheTekknician**, and a warm welcome to our new Pioneers, **Benjamin M** and **Ghislain G**! + ## v2.15.4 ### Changed - Updated Early Access indicators in the Civitai Details page to be more visible diff --git a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs index bed6978bb..12fb063e7 100644 --- a/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/UnixPrerequisiteHelper.cs @@ -697,9 +697,9 @@ public async Task InstallUvIfNecessary(IProgress? progress = nul File.Delete(UvDownloadPath); } - public string? GetGfxArchFromAmdGpuName() + public string? GetGfxArchFromAmdGpuName(GpuInfo? gpu = null) { - var gpu = + gpu ??= settingsManager.Settings.PreferredGpu ?? HardwareHelper.IterGpuInfo().FirstOrDefault(x => x is { Name: not null, IsAmd: true }); @@ -710,54 +710,7 @@ public async Task InstallUvIfNecessary(IProgress? progress = nul var name = gpu.Name; var nameNoSpaces = name.Replace(" ", "", StringComparison.Ordinal); - return name switch - { - // RDNA4 - _ when Has("9060") || Has("9070") => "gfx1201", - - // RDNA3.5 APUs - _ when Has("860M") => "gfx1152", - _ when Has("890M") => "gfx1150", - _ when Has("8040S") || Has("8050S") || Has("8060S") || Has("880M") || Has("Z2 Extreme") => - "gfx1151", - - // RDNA3 APUs (Phoenix) - _ when Has("740M") || Has("760M") || Has("780M") || Has("Z1") || Has("Z2") => "gfx1103", - - // RDNA3 dGPU Navi33 - _ when Has("7400") || Has("7500") || Has("7600") || Has("7650") || Has("7700S") => "gfx1102", - - // RDNA3 dGPU Navi32 - _ when Has("7700") || Has("RX 7800") || HasNoSpace("RX7800") => "gfx1101", - - // RDNA3 dGPU Navi31 (incl. Pro) - _ when Has("W7800") || Has("7900") || Has("7950") || Has("7990") => "gfx1100", - - // RDNA2 APUs (Rembrandt) - _ when Has("660M") || Has("680M") => "gfx1035", - - // RDNA2 Navi24 low-end (incl. some mobiles) - _ when Has("6300") || Has("6400") || Has("6450") || Has("6500") || Has("6550") || Has("6500M") => - "gfx1034", - - // RDNA2 Navi23 - _ when Has("6600") || Has("6650") || Has("6700S") || Has("6800S") || Has("6600M") => "gfx1032", - - // RDNA2 Navi22 (note: desktop 6800 is NOT here; that’s Navi21/gfx1030) - _ when Has("6700") || Has("6750") || Has("6800M") || Has("6850M") => "gfx1031", - - // RDNA2 Navi21 (big die) - _ when Has("6800") || Has("6900") || Has("6950") => "gfx1030", - - _ => null, - }; - - bool HasNoSpace(string s) => - nameNoSpaces.Contains( - s.Replace(" ", "", StringComparison.Ordinal), - StringComparison.OrdinalIgnoreCase - ); - bool Has(string s) => name.Contains(s, StringComparison.OrdinalIgnoreCase); + return gpu.GetAmdGfxArch(); } private async Task DownloadAndExtractPrerequisite( diff --git a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs index 26c281ee2..18ee8741f 100644 --- a/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs +++ b/StabilityMatrix.Avalonia/Helpers/WindowsPrerequisiteHelper.cs @@ -932,67 +932,16 @@ public async Task AddMissingLibsToVenv( // await downloadPath.DeleteAsync(); } - public string? GetGfxArchFromAmdGpuName() + public string? GetGfxArchFromAmdGpuName(GpuInfo? gpu = null) { - var gpu = + gpu ??= settingsManager.Settings.PreferredGpu ?? HardwareHelper.IterGpuInfo().FirstOrDefault(x => x is { Name: not null, IsAmd: true }); if (gpu?.Name is null || !gpu.IsAmd) return null; - // Normalize for safer substring checks (handles RX7800 vs RX 7800, etc.) - var name = gpu.Name; - var nameNoSpaces = name.Replace(" ", "", StringComparison.Ordinal); - - return name switch - { - // RDNA4 - _ when Has("9060") || Has("9070") => "gfx1201", - - // RDNA3.5 APUs - _ when Has("860M") => "gfx1152", - _ when Has("890M") => "gfx1150", - _ when Has("8040S") || Has("8050S") || Has("8060S") || Has("880M") || Has("Z2 Extreme") => - "gfx1151", - - // RDNA3 APUs (Phoenix) - _ when Has("740M") || Has("760M") || Has("780M") || Has("Z1") || Has("Z2") => "gfx1103", - - // RDNA3 dGPU Navi33 - _ when Has("7400") || Has("7500") || Has("7600") || Has("7650") || Has("7700S") => "gfx1102", - - // RDNA3 dGPU Navi32 - _ when Has("7700") || Has("RX 7800") || HasNoSpace("RX7800") => "gfx1101", - - // RDNA3 dGPU Navi31 (incl. Pro) - _ when Has("W7800") || Has("7900") || Has("7950") || Has("7990") => "gfx1100", - - // RDNA2 APUs (Rembrandt) - _ when Has("660M") || Has("680M") => "gfx1035", - - // RDNA2 Navi24 low-end (incl. some mobiles) - _ when Has("6300") || Has("6400") || Has("6450") || Has("6500") || Has("6550") || Has("6500M") => - "gfx1034", - - // RDNA2 Navi23 - _ when Has("6600") || Has("6650") || Has("6700S") || Has("6800S") || Has("6600M") => "gfx1032", - - // RDNA2 Navi22 (note: desktop 6800 is NOT here; that’s Navi21/gfx1030) - _ when Has("6700") || Has("6750") || Has("6800M") || Has("6850M") => "gfx1031", - - // RDNA2 Navi21 (big die) - _ when Has("6800") || Has("6900") || Has("6950") => "gfx1030", - - _ => null, - }; - - bool HasNoSpace(string s) => - nameNoSpaces.Contains( - s.Replace(" ", "", StringComparison.Ordinal), - StringComparison.OrdinalIgnoreCase - ); - bool Has(string s) => name.Contains(s, StringComparison.OrdinalIgnoreCase); + return gpu.GetAmdGfxArch(); } private async Task DownloadAndExtractPrerequisite( diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageGalleryCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageGalleryCardViewModel.cs index 72b6a139a..5de2d6d06 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageGalleryCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageGalleryCardViewModel.cs @@ -105,7 +105,7 @@ or NotifyCollectionChangedAction.Reset { if (sources.Count == 0) { - SelectedImageIndex = 0; + SelectedImageIndex = -1; } else if (SelectedImageIndex == -1) { @@ -159,7 +159,7 @@ private async Task FlyoutPreview(IImage? image) var viewerVm = vmFactory.Get(); viewerVm.ImageSource = new ImageSource((Bitmap)image); - var dialog = new BetterContentDialog { Content = new ImageViewerDialog { DataContext = viewerVm, } }; + var dialog = new BetterContentDialog { Content = new ImageViewerDialog { DataContext = viewerVm } }; await dialog.ShowAsync(); } diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index a95923de8..a8ffb3152 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -602,6 +602,7 @@ private async Task ChangeVersion() viewModel.SelectedBasePackage = basePackage; viewModel.CanSelectBasePackage = false; + viewModel.ShowPythonVersionSelection = false; viewModel.IsReleaseMode = Package.Version?.IsReleaseMode ?? false; var dialog = new TaskDialog diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs index d2cf1c196..f13d7030c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs @@ -44,7 +44,7 @@ IPyInstallationManager pyInstallationManager [ObservableProperty] private string searchFilter = string.Empty; - private SourceCache packageSource = new(p => p.GithubUrl); + private SourceCache packageSource = new(p => p.Name); public IObservableCollection InferencePackages { get; } = new ObservableCollectionExtended(); @@ -119,10 +119,7 @@ protected override void OnInitialLoaded() .ObserveOn(SynchronizationContext.Current) .Subscribe(); - packageSource.EditDiff( - packageFactory.GetAllAvailablePackages(), - (a, b) => a.GithubUrl == b.GithubUrl - ); + packageSource.EditDiff(packageFactory.GetAllAvailablePackages(), (a, b) => a.Name == b.Name); } public void OnPackageSelected(BasePackage? package) diff --git a/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs b/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs index 09bda13f9..9d759e3fb 100644 --- a/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs +++ b/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs @@ -215,6 +215,13 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage) prerequisiteHelper, pyInstallationManager ), + "forge-neo" => new ForgeNeo( + githubApiCache, + settingsManager, + downloadService, + prerequisiteHelper, + pyInstallationManager + ), "framepack" => new FramePack( githubApiCache, settingsManager, @@ -236,6 +243,13 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage) prerequisiteHelper, pyInstallationManager ), + "Wan2GP" => new Wan2GP( + githubApiCache, + settingsManager, + downloadService, + prerequisiteHelper, + pyInstallationManager + ), _ => throw new ArgumentOutOfRangeException(nameof(installedPackage)), }; } diff --git a/StabilityMatrix.Core/Helper/HardwareInfo/GpuInfo.cs b/StabilityMatrix.Core/Helper/HardwareInfo/GpuInfo.cs index f9ab746a4..eedcb556c 100644 --- a/StabilityMatrix.Core/Helper/HardwareInfo/GpuInfo.cs +++ b/StabilityMatrix.Core/Helper/HardwareInfo/GpuInfo.cs @@ -77,42 +77,59 @@ public bool IsWindowsRocmSupportedGpu() if (!IsAmd || string.IsNullOrWhiteSpace(Name)) return null; - var name = Name.ToLowerInvariant(); - - if (name.Contains("9070") || name.Contains("R9700")) - return "gfx1201"; - - if (name.Contains("9060")) - return "gfx1200"; - - if (name.Contains("z2") || name.Contains("880m") || name.Contains("8050s") || name.Contains("8060s")) - return "gfx1151"; - - if (name.Contains("740m") || name.Contains("760m") || name.Contains("780m") || name.Contains("z1")) - return "gfx1103"; - - if ( - name.Contains("w7400") - || name.Contains("w7500") - || name.Contains("w7600") - || name.Contains("7500 xt") - || name.Contains("7600") - || name.Contains("7650 gre") - || name.Contains("7700s") - ) - return "gfx1102"; - - if ( - name.Contains("v710") - || name.Contains("7700") - || (name.Contains("7800") && !name.Contains("w7800")) - ) - return "gfx1101"; - - if (name.Contains("w7800") || name.Contains("7900") || name.Contains("7950") || name.Contains("7990")) - return "gfx1100"; - - return null; + // Normalize for safer substring checks (handles RX7800 vs RX 7800, etc.) + var name = Name; + var nameNoSpaces = name.Replace(" ", "", StringComparison.Ordinal); + + return name switch + { + // RDNA4 + _ when Has("R9700") || Has("9070") => "gfx1201", + _ when Has("9060") => "gfx1200", + + // RDNA3.5 APUs + _ when Has("860M") => "gfx1152", + _ when Has("890M") => "gfx1150", + _ when Has("8040S") || Has("8050S") || Has("8060S") || Has("880M") || Has("Z2 Extreme") => + "gfx1151", + + // RDNA3 APUs (Phoenix) + _ when Has("740M") || Has("760M") || Has("780M") || Has("Z1") || Has("Z2") => "gfx1103", + + // RDNA3 dGPU Navi33 + _ when Has("7400") || Has("7500") || Has("7600") || Has("7650") || Has("7700S") => "gfx1102", + + // RDNA3 dGPU Navi32 + _ when Has("7700") || Has("RX 7800") || HasNoSpace("RX7800") => "gfx1101", + + // RDNA3 dGPU Navi31 (incl. Pro) + _ when Has("W7800") || Has("7900") || Has("7950") || Has("7990") => "gfx1100", + + // RDNA2 APUs (Rembrandt) + _ when Has("660M") || Has("680M") => "gfx1035", + + // RDNA2 Navi24 low-end (incl. some mobiles) + _ when Has("6300") || Has("6400") || Has("6450") || Has("6500") || Has("6550") || Has("6500M") => + "gfx1034", + + // RDNA2 Navi23 + _ when Has("6600") || Has("6650") || Has("6700S") || Has("6800S") || Has("6600M") => "gfx1032", + + // RDNA2 Navi22 (note: desktop 6800 is NOT here; that’s Navi21/gfx1030) + _ when Has("6700") || Has("6750") || Has("6800M") || Has("6850M") => "gfx1031", + + // RDNA2 Navi21 (big die) + _ when Has("6800") || Has("6900") || Has("6950") => "gfx1030", + + _ => null, + }; + + bool HasNoSpace(string s) => + nameNoSpaces.Contains( + s.Replace(" ", "", StringComparison.Ordinal), + StringComparison.OrdinalIgnoreCase + ); + bool Has(string s) => name.Contains(s, StringComparison.OrdinalIgnoreCase); } public virtual bool Equals(GpuInfo? other) diff --git a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs index 02c17638c..2629db9b9 100644 --- a/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs +++ b/StabilityMatrix.Core/Helper/IPrerequisiteHelper.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Runtime.Versioning; using StabilityMatrix.Core.Exceptions; +using StabilityMatrix.Core.Helper.HardwareInfo; using StabilityMatrix.Core.Models; using StabilityMatrix.Core.Models.FileInterfaces; using StabilityMatrix.Core.Models.Packages; @@ -298,5 +299,5 @@ Task AddMissingLibsToVenv( Task InstallPythonIfNecessary(PyVersion version, IProgress? progress = null); Task InstallVirtualenvIfNecessary(PyVersion version, IProgress? progress = null); Task InstallTkinterIfNecessary(PyVersion version, IProgress? progress = null); - string? GetGfxArchFromAmdGpuName(); + string? GetGfxArchFromAmdGpuName(GpuInfo? gpu = null); } diff --git a/StabilityMatrix.Core/Models/PackageModification/InstallSageAttentionStep.cs b/StabilityMatrix.Core/Models/PackageModification/InstallSageAttentionStep.cs index 6577d2208..dbaf7cb0a 100644 --- a/StabilityMatrix.Core/Models/PackageModification/InstallSageAttentionStep.cs +++ b/StabilityMatrix.Core/Models/PackageModification/InstallSageAttentionStep.cs @@ -52,52 +52,72 @@ await pyInstallationManager.GetInstallationAsync(pyVersion).ConfigureAwait(false var torchInfo = await venvRunner.PipShow("torch").ConfigureAwait(false); var sageWheelUrl = string.Empty; - var shortPythonVersionString = pyVersion.Minor switch - { - 10 => "cp310", - 11 => "cp311", - 12 => "cp312", - _ => throw new ArgumentOutOfRangeException("Invalid Python version"), - }; - if (torchInfo == null) - { - sageWheelUrl = string.Empty; - } - else if (torchInfo.Version.Contains("2.5.1") && torchInfo.Version.Contains("cu124")) - { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu124torch2.5.1.post3-cp39-abi3-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.6.0") && torchInfo.Version.Contains("cu126")) - { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu126torch2.6.0.post3-cp39-abi3-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.7.0") && torchInfo.Version.Contains("cu128")) - { - sageWheelUrl = - $"https://github.com/woct0rdho/SageAttention/releases/download/v2.1.1-windows/sageattention-2.1.1+cu128torch2.7.0-{shortPythonVersionString}-{shortPythonVersionString}-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.7.1") && torchInfo.Version.Contains("cu128")) + if (torchInfo != null) { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu128torch2.7.1.post3-cp39-abi3-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.8.0") && torchInfo.Version.Contains("cu128")) - { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu128torch2.8.0.post3-cp39-abi3-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.9.0") && torchInfo.Version.Contains("cu128")) - { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu128torch2.9.0.post3-cp39-abi3-win_amd64.whl"; - } - else if (torchInfo.Version.Contains("2.9.0") && torchInfo.Version.Contains("cu130")) - { - sageWheelUrl = - "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu130torch2.9.0.post3-cp39-abi3-win_amd64.whl"; + // Extract base version (before +) and CUDA index + var versionString = torchInfo.Version; + var plusIndex = versionString.IndexOf('+'); + var baseVersionString = plusIndex >= 0 ? versionString[..plusIndex] : versionString; + var cudaIndex = plusIndex >= 0 ? versionString[(plusIndex + 1)..] : string.Empty; + + // Try to parse base version for comparison + if (Version.TryParse(baseVersionString, out var torchVersion)) + { + var minVersion = new Version(2, 9, 0); + + // New wheels work for torch >= 2.9.0 with cu128 or cu130 + if (torchVersion >= minVersion) + { + if (cudaIndex.Contains("cu128")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post4/sageattention-2.2.0+cu128torch2.9.0andhigher.post4-cp39-abi3-win_amd64.whl"; + } + else if (cudaIndex.Contains("cu130")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post4/sageattention-2.2.0+cu130torch2.9.0andhigher.post4-cp39-abi3-win_amd64.whl"; + } + } + else + { + // Fallback to old wheels for torch < 2.9.0 + var shortPythonVersionString = pyVersion.Minor switch + { + 10 => "cp310", + 11 => "cp311", + 12 => "cp312", + _ => throw new ArgumentOutOfRangeException("Invalid Python version"), + }; + + if (versionString.Contains("2.5.1") && versionString.Contains("cu124")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu124torch2.5.1.post3-cp39-abi3-win_amd64.whl"; + } + else if (versionString.Contains("2.6.0") && versionString.Contains("cu126")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu126torch2.6.0.post3-cp39-abi3-win_amd64.whl"; + } + else if (versionString.Contains("2.7.0") && versionString.Contains("cu128")) + { + sageWheelUrl = + $"https://github.com/woct0rdho/SageAttention/releases/download/v2.1.1-windows/sageattention-2.1.1+cu128torch2.7.0-{shortPythonVersionString}-{shortPythonVersionString}-win_amd64.whl"; + } + else if (versionString.Contains("2.7.1") && versionString.Contains("cu128")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu128torch2.7.1.post3-cp39-abi3-win_amd64.whl"; + } + else if (versionString.Contains("2.8.0") && versionString.Contains("cu128")) + { + sageWheelUrl = + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows.post3/sageattention-2.2.0+cu128torch2.8.0.post3-cp39-abi3-win_amd64.whl"; + } + } + } } var pipArgs = new PipInstallArgs("triton-windows"); diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index c52c9fb37..267196ba4 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -850,7 +850,7 @@ protected PipInstallArgs GetTorchPipArgs( string torchvisionVersion = "", string torchaudioVersion = "", string xformersVersion = "", - string cudaIndex = "cu128", + string cudaIndex = "cu130", string rocmIndex = "rocm6.4" ) { diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 4eba9569c..6af2b047f 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -413,7 +413,7 @@ _ when gfxArch.StartsWith("gfx120") => "https://rocm.nightlies.amd.com/v2/gfx120 RequirementsFilePaths = ["requirements.txt"], ExtraPipArgs = ["numpy<2"], TorchaudioVersion = " ", // Request torchaudio without a specific version - CudaIndex = isLegacyNvidia ? "cu126" : "cu128", + CudaIndex = isLegacyNvidia ? "cu126" : "cu130", RocmIndex = "rocm6.4", UpgradePackages = true, PostInstallPipArgs = ["typing-extensions>=4.15.0"], diff --git a/StabilityMatrix.Core/Models/Packages/ForgeAmdGpu.cs b/StabilityMatrix.Core/Models/Packages/ForgeAmdGpu.cs index b19c5d893..9c1a2632d 100644 --- a/StabilityMatrix.Core/Models/Packages/ForgeAmdGpu.cs +++ b/StabilityMatrix.Core/Models/Packages/ForgeAmdGpu.cs @@ -42,6 +42,8 @@ IPyInstallationManager pyInstallationManager public override bool IsCompatible => HardwareHelper.PreferDirectMLOrZluda(); + public override PackageType PackageType => PackageType.SdInference; + public override IEnumerable Prerequisites => base.Prerequisites.Concat([PackagePrerequisite.HipSdk]); diff --git a/StabilityMatrix.Core/Models/Packages/ForgeClassic.cs b/StabilityMatrix.Core/Models/Packages/ForgeClassic.cs index ec628b789..1aaa28697 100644 --- a/StabilityMatrix.Core/Models/Packages/ForgeClassic.cs +++ b/StabilityMatrix.Core/Models/Packages/ForgeClassic.cs @@ -36,6 +36,7 @@ IPyInstallationManager pyInstallationManager public override IEnumerable AvailableTorchIndices => [TorchIndex.Cuda]; public override bool IsCompatible => HardwareHelper.HasNvidiaGpu(); public override PyVersion RecommendedPythonVersion => Python.PyInstallationManager.Python_3_11_13; + public override PackageType PackageType => PackageType.SdInference; public override List LaunchOptions => [ @@ -169,13 +170,15 @@ public override async Task InstallPackage( var config = new PipInstallConfig { RequirementsFilePaths = requirementsPaths, - TorchaudioVersion = " ", // Request torchaudio installation + TorchVersion = "<2.9.0", + TorchvisionVersion = "<0.24.0", CudaIndex = isLegacyNvidia ? "cu126" : "cu128", UpgradePackages = true, ExtraPipArgs = [ "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip", ], + PostInstallPipArgs = ["numpy==1.26.4"], }; await StandardPipInstallProcessAsync( diff --git a/StabilityMatrix.Core/Models/Packages/ForgeNeo.cs b/StabilityMatrix.Core/Models/Packages/ForgeNeo.cs new file mode 100644 index 000000000..f73be9105 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/ForgeNeo.cs @@ -0,0 +1,22 @@ +using Injectio.Attributes; +using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Helper.Cache; +using StabilityMatrix.Core.Python; +using StabilityMatrix.Core.Services; + +namespace StabilityMatrix.Core.Models.Packages; + +[RegisterSingleton(Duplicate = DuplicateStrategy.Append)] +public class ForgeNeo( + IGithubApiCache githubApi, + ISettingsManager settingsManager, + IDownloadService downloadService, + IPrerequisiteHelper prerequisiteHelper, + IPyInstallationManager pyInstallationManager +) : ForgeClassic(githubApi, settingsManager, downloadService, prerequisiteHelper, pyInstallationManager) +{ + public override string Name => "forge-neo"; + public override string DisplayName { get; set; } = "Stable Diffusion WebUI Forge - Neo"; + public override string MainBranch => "neo"; + public override PackageType PackageType => PackageType.SdInference; +} diff --git a/StabilityMatrix.Core/Models/Packages/PipInstallConfig.cs b/StabilityMatrix.Core/Models/Packages/PipInstallConfig.cs index 885754ed1..320915b22 100644 --- a/StabilityMatrix.Core/Models/Packages/PipInstallConfig.cs +++ b/StabilityMatrix.Core/Models/Packages/PipInstallConfig.cs @@ -14,7 +14,7 @@ public record PipInstallConfig public string TorchvisionVersion { get; init; } = ""; public string TorchaudioVersion { get; init; } = ""; public string XformersVersion { get; init; } = ""; - public string CudaIndex { get; init; } = "cu129"; + public string CudaIndex { get; init; } = "cu130"; public string RocmIndex { get; init; } = "rocm6.4"; public bool ForceReinstallTorch { get; init; } = true; public bool UpgradePackages { get; init; } = false; diff --git a/StabilityMatrix.Core/Models/Packages/Reforge.cs b/StabilityMatrix.Core/Models/Packages/Reforge.cs index 7e2723cc1..71be0f84a 100644 --- a/StabilityMatrix.Core/Models/Packages/Reforge.cs +++ b/StabilityMatrix.Core/Models/Packages/Reforge.cs @@ -26,4 +26,5 @@ IPyInstallationManager pyInstallationManager public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/reforge/preview.webp"); public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Recommended; public override bool OfferInOneClickInstaller => true; + public override PackageType PackageType => PackageType.SdInference; } diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index 3f9e6ba54..09d33024c 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -37,6 +37,7 @@ IPyInstallationManager pyInstallationManager public override bool ShouldIgnoreReleases => true; public override IPackageExtensionManager ExtensionManager => null; public override PackageDifficulty InstallerSortOrder => PackageDifficulty.ReallyRecommended; + public override PackageType PackageType => PackageType.Legacy; public override List LaunchOptions => [ diff --git a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs index e42c9d078..1ed8007d6 100644 --- a/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs +++ b/StabilityMatrix.Core/Models/Packages/VladAutomatic.cs @@ -205,6 +205,13 @@ IPyInstallationManager pyInstallationManager Options = ["--port"], }, new() + { + Name = "Use uv", + Type = LaunchOptionType.Bool, + InitialValue = true, + Options = ["--uv"], + }, + new() { Name = "VRAM", Type = LaunchOptionType.Bool, @@ -384,7 +391,7 @@ void HandleConsoleOutput(ProcessOutput s) } VenvRunner.RunDetached( - [Path.Combine(installLocation, options.Command ?? LaunchCommand), "--uv", .. options.Arguments], + [Path.Combine(installLocation, options.Command ?? LaunchCommand), .. options.Arguments], HandleConsoleOutput, OnExit ); diff --git a/StabilityMatrix.Core/Models/Packages/Wan2GP.cs b/StabilityMatrix.Core/Models/Packages/Wan2GP.cs new file mode 100644 index 000000000..fe2db5db1 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/Wan2GP.cs @@ -0,0 +1,413 @@ +using System.Collections.Immutable; +using System.Text.RegularExpressions; +using Injectio.Attributes; +using StabilityMatrix.Core.Helper; +using StabilityMatrix.Core.Helper.Cache; +using StabilityMatrix.Core.Helper.HardwareInfo; +using StabilityMatrix.Core.Models.FileInterfaces; +using StabilityMatrix.Core.Models.Progress; +using StabilityMatrix.Core.Processes; +using StabilityMatrix.Core.Python; +using StabilityMatrix.Core.Services; + +namespace StabilityMatrix.Core.Models.Packages; + +/// +/// Package for Wan2GP - Super Optimized Gradio UI for AI video creation. +/// Supports Wan 2.1/2.2, Qwen, Hunyuan Video, LTX Video and Flux. +/// https://github.com/deepbeepmeep/Wan2GP +/// +/// +/// Model Sharing: This package does not support Stability Matrix shared folder configuration. +/// Wan2GP manages model paths through its own wgp_config.json file, which is created and managed +/// by the Gradio UI on first launch. Users should configure model paths via the Settings tab +/// in the Wan2GP UI. +/// +[RegisterSingleton(Duplicate = DuplicateStrategy.Append)] +public class Wan2GP( + IGithubApiCache githubApi, + ISettingsManager settingsManager, + IDownloadService downloadService, + IPrerequisiteHelper prerequisiteHelper, + IPyInstallationManager pyInstallationManager +) : BaseGitPackage(githubApi, settingsManager, downloadService, prerequisiteHelper, pyInstallationManager) +{ + public override string Name => "Wan2GP"; + public override string DisplayName { get; set; } = "Wan2GP"; + public override string Author => "deepbeepmeep"; + + public override string Blurb => + "Super Optimized Gradio UI for AI video creation for GPU poor machines (6GB+ VRAM). " + + "Supports Wan 2.1/2.2, Qwen, Hunyuan Video, LTX Video and Flux."; + + public override string LicenseType => "Apache-2.0"; + public override string LicenseUrl => "https://github.com/deepbeepmeep/Wan2GP/blob/main/LICENSE.txt"; + public override string LaunchCommand => "wgp.py"; + + public override Uri PreviewImageUri => new("https://cdn.lykos.ai/sm/packages/wan2gp/wan2gp.webp"); + + public override string OutputFolderName => "outputs"; + public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Advanced; + public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.None; + + public override IEnumerable AvailableSharedFolderMethods => [SharedFolderMethod.None]; + + public override IEnumerable AvailableTorchIndices => [TorchIndex.Cuda, TorchIndex.Rocm]; + + public override bool IsCompatible => HardwareHelper.HasNvidiaGpu() || HardwareHelper.HasAmdGpu(); + + public override string MainBranch => "main"; + public override bool ShouldIgnoreReleases => true; + + public override Dictionary>? SharedOutputFolders => + new() { [SharedOutputType.Img2Vid] = ["outputs"] }; + + // AMD ROCm requires Python 3.11, NVIDIA uses 3.10 + public override PyVersion RecommendedPythonVersion => + IsAmdRocm ? Python.PyInstallationManager.Python_3_11_13 : Python.PyInstallationManager.Python_3_10_17; + + public override string Disclaimer => + IsAmdRocm && Compat.IsWindows + ? "AMD GPU support on Windows is experimental. Supported GPUs: 7900(XT), 7800(XT), 7600(XT), Phoenix, 9070(XT) and Strix Halo." + : string.Empty; + + /// + /// Helper property to check if we're using AMD ROCm + /// + private bool IsAmdRocm => GetRecommendedTorchVersion() == TorchIndex.Rocm; + + public override List LaunchOptions => + [ + new() + { + Name = "Host", + Type = LaunchOptionType.String, + DefaultValue = "127.0.0.1", + Options = ["--server"], + }, + new() + { + Name = "Port", + Type = LaunchOptionType.String, + DefaultValue = "7860", + Options = ["--port"], + }, + new() + { + Name = "Share", + Type = LaunchOptionType.Bool, + Description = "Set whether to share on Gradio", + Options = ["--share"], + }, + new() + { + Name = "Multiple Images", + Type = LaunchOptionType.Bool, + Description = "Enable multiple images mode", + InitialValue = true, + Options = ["--multiple-images"], + }, + new() + { + Name = "Compile", + Type = LaunchOptionType.Bool, + Description = "Enable model compilation for faster inference (may not work on all systems)", + Options = ["--compile"], + }, + LaunchOptionDefinition.Extras, + ]; + + public override TorchIndex GetRecommendedTorchVersion() + { + // Check for AMD ROCm support (Windows or Linux) + var preferRocm = + ( + Compat.IsWindows + && ( + SettingsManager.Settings.PreferredGpu?.IsWindowsRocmSupportedGpu() + ?? HardwareHelper.HasWindowsRocmSupportedGpu() + ) + ) + || ( + Compat.IsLinux + && (SettingsManager.Settings.PreferredGpu?.IsAmd ?? HardwareHelper.PreferRocm()) + ); + + if (preferRocm) + { + return TorchIndex.Rocm; + } + + // NVIDIA CUDA + if (SettingsManager.Settings.PreferredGpu?.IsNvidia ?? HardwareHelper.HasNvidiaGpu()) + { + return TorchIndex.Cuda; + } + + return base.GetRecommendedTorchVersion(); + } + + public override async Task InstallPackage( + string installLocation, + InstalledPackage installedPackage, + InstallPackageOptions options, + IProgress? progress = null, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default + ) + { + var torchIndex = options.PythonOptions.TorchIndex ?? GetRecommendedTorchVersion(); + + progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true)); + await using var venvRunner = await SetupVenvPure( + installLocation, + pythonVersion: options.PythonOptions.PythonVersion + ) + .ConfigureAwait(false); + + if (torchIndex == TorchIndex.Rocm) + { + await InstallAmdRocmAsync( + venvRunner, + installedPackage, + options, + progress, + onConsoleOutput, + cancellationToken + ) + .ConfigureAwait(false); + } + else + { + await InstallNvidiaAsync( + venvRunner, + installedPackage, + options, + progress, + onConsoleOutput, + cancellationToken + ) + .ConfigureAwait(false); + } + + progress?.Report(new ProgressReport(1, "Install complete", isIndeterminate: false)); + } + + private async Task InstallNvidiaAsync( + IPyVenvRunner venvRunner, + InstalledPackage installedPackage, + InstallPackageOptions options, + IProgress? progress, + Action? onConsoleOutput, + CancellationToken cancellationToken + ) + { + var isLegacyNvidia = + SettingsManager.Settings.PreferredGpu?.IsLegacyNvidiaGpu() ?? HardwareHelper.HasLegacyNvidiaGpu(); + var isNewerNvidia = + SettingsManager.Settings.PreferredGpu?.IsAmpereOrNewerGpu() + ?? HardwareHelper.HasAmpereOrNewerGpu(); + + // Platform-specific versions from pinokio torch.js + // Windows: torch 2.7.1, Linux: torch 2.7.0 (to match prebuilt attention wheel requirements) + var torchVersion = Compat.IsWindows ? "2.7.1" : "2.7.0"; + var torchvisionVersion = Compat.IsWindows ? "0.22.1" : "0.22.0"; + var torchaudioVersion = Compat.IsWindows ? "2.7.1" : "2.7.0"; + var cudaIndex = isLegacyNvidia ? "cu126" : "cu128"; + + progress?.Report(new ProgressReport(-1f, "Upgrading pip...", isIndeterminate: true)); + await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); + + // Install requirements directly using -r flag (handles @ URL syntax properly) + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + await venvRunner.PipInstall("-r requirements.txt", onConsoleOutput).ConfigureAwait(false); + + // Install torch with specific versions and CUDA index (force reinstall to ensure correct version) + progress?.Report(new ProgressReport(-1f, "Installing PyTorch...", isIndeterminate: true)); + var torchArgs = new PipInstallArgs() + .WithTorch($"=={torchVersion}") + .WithTorchVision($"=={torchvisionVersion}") + .WithTorchAudio($"=={torchaudioVersion}") + .WithXFormers("==0.0.30") + .WithTorchExtraIndex(cudaIndex) + .AddArg("--force-reinstall") + .AddArg("--no-deps"); + + await venvRunner.PipInstall(torchArgs, onConsoleOutput).ConfigureAwait(false); + + // Install hf-xet and pin setuptools to avoid distutils compatibility issues with Python 3.10 + await venvRunner.PipInstall("hf-xet \"setuptools<70.0.0\"", onConsoleOutput).ConfigureAwait(false); + + // Install triton-windows for newer NVIDIA GPUs on Windows + if (Compat.IsWindows && isNewerNvidia) + { + progress?.Report(new ProgressReport(-1f, "Installing triton-windows...", isIndeterminate: true)); + await venvRunner + .PipInstall("triton-windows==3.3.1.post19", onConsoleOutput) + .ConfigureAwait(false); + } + + // Install SageAttention and Flash Attention + if (Compat.IsWindows) + { + progress?.Report(new ProgressReport(-1f, "Installing SageAttention...", isIndeterminate: true)); + await venvRunner + .PipInstall( + "https://github.com/woct0rdho/SageAttention/releases/download/v2.2.0-windows/sageattention-2.2.0+cu128torch2.7.1-cp310-cp310-win_amd64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + progress?.Report(new ProgressReport(-1f, "Installing Flash Attention...", isIndeterminate: true)); + await venvRunner + .PipInstall( + "https://huggingface.co/lldacing/flash-attention-windows-wheel/resolve/main/flash_attn-2.7.4.post1%2Bcu128torch2.7.0cxx11abiFALSE-cp310-cp310-win_amd64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + } + else if (Compat.IsLinux) + { + progress?.Report(new ProgressReport(-1f, "Installing SageAttention...", isIndeterminate: true)); + await venvRunner + .PipInstall( + "https://huggingface.co/MonsterMMORPG/SECourses_Premium_Flash_Attention/resolve/main/sageattention-2.1.1-cp310-cp310-linux_x86_64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + progress?.Report(new ProgressReport(-1f, "Installing Flash Attention...", isIndeterminate: true)); + await venvRunner + .PipInstall( + "https://github.com/kingbri1/flash-attention/releases/download/v2.7.4.post1/flash_attn-2.7.4.post1+cu128torch2.7.0cxx11abiFALSE-cp310-cp310-linux_x86_64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + await venvRunner.PipInstall("numpy==2.1.2", onConsoleOutput).ConfigureAwait(false); + } + } + + private async Task InstallAmdRocmAsync( + IPyVenvRunner venvRunner, + InstalledPackage installedPackage, + InstallPackageOptions options, + IProgress? progress, + Action? onConsoleOutput, + CancellationToken cancellationToken + ) + { + progress?.Report(new ProgressReport(-1f, "Upgrading pip...", isIndeterminate: true)); + await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); + + if (Compat.IsWindows) + { + // Windows AMD ROCm - special TheRock wheels + progress?.Report( + new ProgressReport(-1f, "Installing PyTorch ROCm wheels...", isIndeterminate: true) + ); + + // Set environment variable for wheel filename check bypass + venvRunner.UpdateEnvironmentVariables(env => env.SetItem("UV_SKIP_WHEEL_FILENAME_CHECK", "1")); + + // Install PyTorch ROCm wheels from TheRock releases (Python 3.11) + await venvRunner + .PipInstall( + "https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch-gfx110x/torch-2.7.0a0+rocm_git3f903c3-cp311-cp311-win_amd64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + await venvRunner + .PipInstall( + "https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch-gfx110x/torchaudio-2.7.0a0+52638ef-cp311-cp311-win_amd64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + await venvRunner + .PipInstall( + "https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch-gfx110x/torchvision-0.22.0+9eb57cd-cp311-cp311-win_amd64.whl", + onConsoleOutput + ) + .ConfigureAwait(false); + + // Install requirements directly using -r flag (handles @ URL syntax properly) + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + await venvRunner.PipInstall("-r requirements.txt", onConsoleOutput).ConfigureAwait(false); + + // Install additional packages + await venvRunner + .PipInstall("hf-xet setuptools numpy==1.26.4", onConsoleOutput) + .ConfigureAwait(false); + } + else + { + // Linux AMD ROCm - standard PyTorch ROCm + // Install requirements directly using -r flag (handles @ URL syntax properly) + progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); + await venvRunner.PipInstall("-r requirements.txt", onConsoleOutput).ConfigureAwait(false); + + // Install torch with ROCm index (force reinstall to ensure correct version) + progress?.Report(new ProgressReport(-1f, "Installing PyTorch ROCm...", isIndeterminate: true)); + var torchArgs = new PipInstallArgs() + .WithTorch("==2.7.0") + .WithTorchVision("==0.22.0") + .WithTorchAudio("==2.7.0") + .WithTorchExtraIndex("rocm6.3") + .AddArg("--force-reinstall") + .AddArg("--no-deps"); + + await venvRunner.PipInstall(torchArgs, onConsoleOutput).ConfigureAwait(false); + + // Install additional packages + await venvRunner + .PipInstall("hf-xet setuptools numpy==1.26.4", onConsoleOutput) + .ConfigureAwait(false); + } + } + + public override async Task RunPackage( + string installLocation, + InstalledPackage installedPackage, + RunPackageOptions options, + Action? onConsoleOutput = null, + CancellationToken cancellationToken = default + ) + { + await SetupVenv(installLocation, pythonVersion: PyVersion.Parse(installedPackage.PythonVersion)) + .ConfigureAwait(false); + + // Fix for distutils compatibility issue with Python 3.10 and setuptools + VenvRunner.UpdateEnvironmentVariables(env => env.SetItem("SETUPTOOLS_USE_DISTUTILS", "stdlib")); + + // Notify user that the package is starting (loading can take a while) + onConsoleOutput?.Invoke( + new ProcessOutput { Text = "Launching Wan2GP, please wait while the UI initializes...\n" } + ); + + VenvRunner.RunDetached( + [Path.Combine(installLocation, options.Command ?? LaunchCommand), .. options.Arguments], + HandleConsoleOutput, + OnExit + ); + + return; + + void HandleConsoleOutput(ProcessOutput s) + { + onConsoleOutput?.Invoke(s); + + if (!s.Text.Contains("Running on", StringComparison.OrdinalIgnoreCase)) + return; + + var regex = new Regex(@"(https?:\/\/)([^:\s]+):(\d+)"); + var match = regex.Match(s.Text); + if (match.Success) + { + WebUrl = match.Value; + OnStartupComplete(WebUrl); + } + } + } +}