diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ebe1ac..a14178d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,22 @@ 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.10.1 +### Added +- Added SVD Shared Model & Output Folders for Forge (fixes [#580](https://github.com/LykosAI/StabilityMatrix/issues/580)) +### Changed +- Improved error message when logging in with a Lykos account fails due to incorrect email or password +- Model Browser & Workflow Browser now auto-load when first navigating to those pages +- Removed update confirmation dialog, instead showing the new version in the update button tooltip ### Fixed +- Fixed package launch not working when environment variable `SETUPTOOLS_USE_DISTUTILS` is set due to conflict with a default environment variable. User environment variables will now correctly override any default environment variables. +- Fixed "No refresh token found" error when failing to login with Lykos account in some cases +- Fixed blank entries appearing in the Categories dropdown on the Checkpoints page +- Fixed crash when loading invalid connected model info files +- Fixed [#585](https://github.com/LykosAI/StabilityMatrix/issues/585) - Crash when drag & drop source and destination are the same - Fixed [#584](https://github.com/LykosAI/StabilityMatrix/issues/584) - `--launch-package` argument not working - Fixed [#581](https://github.com/LykosAI/StabilityMatrix/issues/581) - Inference teaching tip showing more often than it should +- Fixed [#578](https://github.com/LykosAI/StabilityMatrix/issues/578) - "python setup.py egg_info did not run successfully" failure when installing Auto1111 or SDWebUI Forge +- Fixed [#574](https://github.com/LykosAI/StabilityMatrix/issues/574) - local images not showing on macOS or Linux ## v2.10.0 ### Added diff --git a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml index b34b8b42..5609a5f7 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml +++ b/StabilityMatrix.Avalonia/Controls/Inference/ImageFolderCard.axaml @@ -11,6 +11,7 @@ xmlns:scroll="clr-namespace:StabilityMatrix.Avalonia.Controls.Scroll" xmlns:labs="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls" xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs" + xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" x:DataType="vmInference:ImageFolderCardViewModel"> @@ -20,6 +21,8 @@ + + @@ -200,7 +203,7 @@ new Uri(str), string str => new Uri("file://" + str), IFormattable formattable => new Uri("file://" + formattable.ToString(null, culture)), _ => null diff --git a/StabilityMatrix.Avalonia/Services/INavigationService.cs b/StabilityMatrix.Avalonia/Services/INavigationService.cs index 68f7f261..690966da 100644 --- a/StabilityMatrix.Avalonia/Services/INavigationService.cs +++ b/StabilityMatrix.Avalonia/Services/INavigationService.cs @@ -39,4 +39,5 @@ public interface INavigationService<[SuppressMessage("ReSharper", "UnusedTypePar bool GoBack(); bool CanGoBack { get; } + object? CurrentPageDataContext { get; } } diff --git a/StabilityMatrix.Avalonia/Services/NavigationService.cs b/StabilityMatrix.Avalonia/Services/NavigationService.cs index 8778f7ca..9e6ac801 100644 --- a/StabilityMatrix.Avalonia/Services/NavigationService.cs +++ b/StabilityMatrix.Avalonia/Services/NavigationService.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Avalonia.Controls; using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Navigation; @@ -190,4 +191,6 @@ public class NavigationService : INavigationService } public bool CanGoBack => _frame?.CanGoBack ?? false; + + public object? CurrentPageDataContext => (_frame?.Content as Control)?.DataContext; } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index ebf5401a..26364b0d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -177,6 +177,8 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScro model => model.ShowNsfw, settings => settings.ModelBrowserNsfwEnabled ); + + SearchModelsCommand.ExecuteAsync(false); } /// diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFile.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFile.cs index baebb0fd..15eb4f5d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFile.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFile.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Avalonia.Data; using CommunityToolkit.Mvvm.ComponentModel; @@ -10,7 +11,6 @@ using CommunityToolkit.Mvvm.Input; using FluentAvalonia.UI.Controls; using Microsoft.Extensions.DependencyInjection; using NLog; -using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; @@ -333,8 +333,15 @@ public partial class CheckpointFile : ViewModelBase if (File.Exists(jsonPath)) { var json = File.ReadAllText(jsonPath); - var connectedModelInfo = ConnectedModelInfo.FromJson(json); - checkpointFile.ConnectedModel = connectedModelInfo; + try + { + var connectedModelInfo = ConnectedModelInfo.FromJson(json); + checkpointFile.ConnectedModel = connectedModelInfo; + } + catch (JsonException) + { + checkpointFile.ConnectedModel = null; + } } checkpointFile.PreviewImagePath = SupportedImageExtensions diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs index 39408129..5f23e3fc 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs @@ -92,7 +92,8 @@ public partial class CheckpointFolder : ViewModelBase public string TitleWithFilesCount => CheckpointFiles.Any() || SubFolders.Any(f => f.CheckpointFiles.Any()) - ? $"{FolderType.GetDescription() ?? FolderType.GetStringValue()} ({CheckpointFiles.Count + SubFolders.Sum(folder => folder.CheckpointFiles.Count)})" + ? $"{FolderType.GetDescription() ?? (string.IsNullOrWhiteSpace(FolderType.GetStringValue()) ? Path.GetFileName(DirectoryPath) : FolderType.GetStringValue())} " + + $"({CheckpointFiles.Count + SubFolders.Sum(folder => folder.CheckpointFiles.Count)})" : FolderType.GetDescription() ?? FolderType.GetStringValue(); public ProgressViewModel Progress { get; } = new(); @@ -447,6 +448,22 @@ public partial class CheckpointFolder : ViewModelBase Progress.Value = 0; var copyPaths = files.ToDictionary(k => k, v => Path.Combine(DirectoryPath, Path.GetFileName(v))); + // remove files that are already in the folder + foreach (var (source, destination) in copyPaths) + { + if (source == destination) + { + copyPaths.Remove(source); + } + } + + if (copyPaths.Count == 0) + { + Progress.Text = "Import complete"; + Progress.Value = 100; + return; + } + var progress = new Progress(report => { Progress.IsIndeterminate = false; diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs index 471d052b..7dd14a8b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/LykosLoginViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Net; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -90,7 +91,15 @@ public partial class LykosLoginViewModel : TaskDialogViewModelBase } catch (ApiException e) { - LoginError = new AppException("Failed to login", $"{e.StatusCode} - {e.Message}"); + LoginError = e.StatusCode switch + { + HttpStatusCode.Unauthorized + => new AppException( + "Incorrect email or password", + "Please try again or reset your password" + ), + _ => new AppException("Failed to login", $"{e.StatusCode} - {e.Message}") + }; } } diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs index de438ecc..cc13e869 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs @@ -12,7 +12,6 @@ using DynamicData.Binding; using FluentAvalonia.UI.Controls; using Refit; using StabilityMatrix.Avalonia.Controls; -using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; @@ -36,8 +35,7 @@ public partial class OpenArtBrowserViewModel( IOpenArtApi openArtApi, INotificationService notificationService, ISettingsManager settingsManager, - IPackageFactory packageFactory, - ServiceManager vmFactory + IPackageFactory packageFactory ) : TabViewModelBase, IInfinitelyScroll { private const int PageSize = 20; @@ -90,6 +88,7 @@ public partial class OpenArtBrowserViewModel( { searchResultsCache.Connect().DeferUntilLoaded().Bind(SearchResults).Subscribe(); SelectedSortMode = AllSortModes.First(); + DoSearch().SafeFireAndForget(); } [RelayCommand] diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 71d624ec..7d38ca8d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -95,6 +95,9 @@ public partial class PackageCardViewModel( [ObservableProperty] private bool showWebUiButton; + [ObservableProperty] + private DownloadPackageVersionOptions? updateVersion; + private void RunningPackagesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (runningPackageService.RunningPackages.Select(x => x.Value) is not { } runningPackages) @@ -196,6 +199,10 @@ public partial class PackageCardViewModel( } IsUpdateAvailable = await HasUpdate(); + if (IsUpdateAvailable) + { + UpdateVersion = await basePackage.GetUpdate(currentPackage); + } if ( Package != null @@ -426,21 +433,6 @@ public partial class PackageCardViewModel( versionOptions.CommitHash = latest.Sha; } - var confirmationDialog = new BetterContentDialog - { - Title = Resources.Label_AreYouSure, - Content = - $"{Package.DisplayName} will be updated to the latest version ({versionOptions.GetReadableVersionString()})", - PrimaryButtonText = Resources.Action_Continue, - SecondaryButtonText = Resources.Action_Cancel, - DefaultButton = ContentDialogButton.Primary, - IsSecondaryButtonEnabled = true, - }; - - var dialogResult = await confirmationDialog.ShowAsync(); - if (dialogResult != ContentDialogResult.Primary) - return; - var updatePackageStep = new UpdatePackageStep( settingsManager, Package, @@ -672,6 +664,7 @@ public partial class PackageCardViewModel( try { var hasUpdate = await basePackage.CheckForUpdates(Package); + UpdateVersion = await basePackage.GetUpdate(Package); await using (settingsManager.BeginTransaction()) { diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs index 6c24efc2..5766a8a8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs @@ -283,6 +283,13 @@ public partial class PackageInstallDetailViewModel( if (!runner.Failed) { + if (ReferenceEquals(this, packageNavigationService.CurrentPageDataContext)) + { + packageNavigationService.GoBack(); + packageNavigationService.GoBack(); + await Task.Delay(100); + } + EventManager.Instance.OnInstalledPackagesChanged(); } } diff --git a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml index facb1298..61c0afd4 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointsPage.axaml @@ -31,6 +31,7 @@ x:Key="TextDropShadowEffect" /> + @@ -143,7 +144,7 @@ + + + + + @@ -177,7 +183,7 @@ ImageHeight="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).ImageSize.Height}" ImageWidth="{Binding $parent[ItemsRepeater].((vm:OutputsPageViewModel)DataContext).ImageSize.Width}" IsSelected="{Binding IsSelected}" - Source="{Binding ImageFile.AbsolutePath}"> + Source="{Binding ImageFile.AbsolutePath, Converter={StaticResource FileUriConverter}}"> + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index 5fb2d8a4..15eea9f1 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -82,19 +82,6 @@ Symbol="Alert" /> - - - - - - - - @@ -215,7 +202,7 @@ - + + + + + + + + + + + ( r => r.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden - && r.RequestMessage?.Headers.Authorization - is { Scheme: "Bearer", Parameter: not null } + && r.RequestMessage?.Headers.Authorization is { Scheme: "Bearer", Parameter: { } param } + && !string.IsNullOrWhiteSpace(param) ) .RetryAsync( async (result, _) => @@ -35,9 +35,7 @@ public class TokenAuthHeaderHandler : DelegatingHandler "Refreshing access token for status ({StatusCode})", result.Result.StatusCode ); - var (newToken, _) = await tokenProvider - .RefreshTokensAsync() - .ConfigureAwait(false); + var (newToken, _) = await tokenProvider.RefreshTokensAsync().ConfigureAwait(false); Logger.Info( "Access token refreshed: {OldToken} -> {NewToken}", @@ -46,10 +44,6 @@ public class TokenAuthHeaderHandler : DelegatingHandler ); } ); - - // InnerHandler must be left as null when using DI, but must be assigned a value when - // using RestService.For - // InnerHandler = new HttpClientHandler(); } protected override Task SendAsync( @@ -59,9 +53,17 @@ public class TokenAuthHeaderHandler : DelegatingHandler { return policy.ExecuteAsync(async () => { - var accessToken = await tokenProvider.GetAccessTokenAsync().ConfigureAwait(false); + // Only add if Authorization is already set to Bearer and access token is not empty + // this allows some routes to not use the access token + if (request.Headers.Authorization is { Scheme: "Bearer" }) + { + var accessToken = await tokenProvider.GetAccessTokenAsync().ConfigureAwait(false); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + } + } return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); }); diff --git a/StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs b/StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs index da41388a..2be76030 100644 --- a/StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs +++ b/StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs @@ -10,4 +10,6 @@ public class DownloadPackageVersionOptions public string GetReadableVersionString() => !string.IsNullOrWhiteSpace(VersionTag) ? VersionTag : $"{BranchName}@{CommitHash?[..7]}"; + + public string ReadableVersionString => GetReadableVersionString(); } diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 9635cecc..9e9b5b80 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -66,7 +66,8 @@ public class A3WebUI( [SharedFolderType.T2IAdapter] = new[] { "models/controlnet/T2IAdapter" }, [SharedFolderType.IpAdapter] = new[] { "models/controlnet/IpAdapter" }, [SharedFolderType.InvokeIpAdapters15] = new[] { "models/controlnet/DiffusersIpAdapters" }, - [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/controlnet/DiffusersIpAdaptersXL" } + [SharedFolderType.InvokeIpAdaptersXl] = new[] { "models/controlnet/DiffusersIpAdaptersXL" }, + [SharedFolderType.SVD] = new[] { "models/svd" } }; public override Dictionary>? SharedOutputFolders => @@ -77,7 +78,8 @@ public class A3WebUI( [SharedOutputType.Img2Img] = new[] { "output/img2img-images" }, [SharedOutputType.Text2Img] = new[] { "output/txt2img-images" }, [SharedOutputType.Img2ImgGrids] = new[] { "output/img2img-grids" }, - [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" } + [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" }, + [SharedOutputType.SVD] = new[] { "output/svd" } }; [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")] @@ -204,6 +206,8 @@ public class A3WebUI( await using var venvRunner = new PyVenvRunner(venvPath); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index 86a103c5..e368790d 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -345,6 +345,54 @@ public abstract class BaseGitPackage : BasePackage } } + public override async Task GetUpdate(InstalledPackage installedPackage) + { + var currentVersion = installedPackage.Version; + if (currentVersion is null or { InstalledReleaseVersion: null, InstalledBranch: null }) + { + Logger.Warn( + "Could not check updates for package {Name}, version is invalid: {@currentVersion}", + Name, + currentVersion + ); + return null; + } + + var versionOptions = new DownloadPackageVersionOptions { IsLatest = true }; + + try + { + if (currentVersion.IsReleaseMode) + { + var latestVersion = await GetLatestVersion(currentVersion.IsPrerelease).ConfigureAwait(false); + versionOptions.IsPrerelease = latestVersion.IsPrerelease; + versionOptions.VersionTag = latestVersion.VersionTag; + return versionOptions; + } + + var allCommits = ( + await GetAllCommits(currentVersion.InstalledBranch!).ConfigureAwait(false) + )?.ToList(); + + if (allCommits == null || !allCommits.Any()) + { + Logger.Warn("No commits found for {Package}", installedPackage.PackageName); + return null; + } + var latestCommitHash = allCommits.First().Sha; + + versionOptions.CommitHash = latestCommitHash; + versionOptions.BranchName = currentVersion.InstalledBranch; + + return versionOptions; + } + catch (ApiException e) + { + Logger.Warn(e, "Failed to check for package updates"); + return null; + } + } + public override async Task Update( InstalledPackage installedPackage, TorchVersion torchVersion, diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 368cf2bc..a603c2a4 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -237,4 +237,6 @@ public abstract class BasePackage onConsoleOutput ); } + + public abstract Task GetUpdate(InstalledPackage installedPackage); } diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index c620182c..61c10f96 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -195,8 +195,9 @@ public class ComfyUI( // Setup venv await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; - await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); progress?.Report( @@ -245,6 +246,7 @@ public class ComfyUI( excludePattern: "torch" ); + await venvRunner.PipUninstall("xformers", onConsoleOutput).ConfigureAwait(false); await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false); progress?.Report(new ProgressReport(1, "Installed Package Requirements", isIndeterminate: false)); diff --git a/StabilityMatrix.Core/Models/Packages/Fooocus.cs b/StabilityMatrix.Core/Models/Packages/Fooocus.cs index 2faaab4f..fcaff953 100644 --- a/StabilityMatrix.Core/Models/Packages/Fooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/Fooocus.cs @@ -193,6 +193,7 @@ public class Fooocus( ) { var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); diff --git a/StabilityMatrix.Core/Models/Packages/FooocusMre.cs b/StabilityMatrix.Core/Models/Packages/FooocusMre.cs index 82497f0f..4ecaea25 100644 --- a/StabilityMatrix.Core/Models/Packages/FooocusMre.cs +++ b/StabilityMatrix.Core/Models/Packages/FooocusMre.cs @@ -111,6 +111,7 @@ public class FooocusMre( ) { var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; progress?.Report(new ProgressReport(-1f, "Installing torch...", isIndeterminate: true)); diff --git a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs index 594f95ec..701da699 100644 --- a/StabilityMatrix.Core/Models/Packages/KohyaSs.cs +++ b/StabilityMatrix.Core/Models/Packages/KohyaSs.cs @@ -126,9 +126,12 @@ public class KohyaSs( .ConfigureAwait(false); progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true)); + // Setup venv await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); // Extra dep needed before running setup since v23.0.x diff --git a/StabilityMatrix.Core/Models/Packages/OneTrainer.cs b/StabilityMatrix.Core/Models/Packages/OneTrainer.cs index d4a92c34..4a6887e6 100644 --- a/StabilityMatrix.Core/Models/Packages/OneTrainer.cs +++ b/StabilityMatrix.Core/Models/Packages/OneTrainer.cs @@ -57,6 +57,8 @@ public class OneTrainer( await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); progress?.Report(new ProgressReport(-1f, "Installing requirements", isIndeterminate: true)); diff --git a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs index 96dc5d65..194b431e 100644 --- a/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs +++ b/StabilityMatrix.Core/Models/Packages/RuinedFooocus.cs @@ -116,6 +116,7 @@ public class RuinedFooocus( if (torchVersion == TorchVersion.Cuda) { var venvRunner = await SetupVenv(installLocation, forceRecreate: true).ConfigureAwait(false); + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true)); diff --git a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs index f64a4197..e3be760f 100644 --- a/StabilityMatrix.Core/Models/Packages/SDWebForge.cs +++ b/StabilityMatrix.Core/Models/Packages/SDWebForge.cs @@ -41,17 +41,6 @@ public class SDWebForge( public override string OutputFolderName => "output"; public override PackageDifficulty InstallerSortOrder => PackageDifficulty.ReallyRecommended; - public override Dictionary>? SharedOutputFolders => - new() - { - [SharedOutputType.Extras] = new[] { "output/extras-images" }, - [SharedOutputType.Saved] = new[] { "log/images" }, - [SharedOutputType.Img2Img] = new[] { "output/img2img-images" }, - [SharedOutputType.Text2Img] = new[] { "output/txt2img-images" }, - [SharedOutputType.Img2ImgGrids] = new[] { "output/img2img-grids" }, - [SharedOutputType.Text2ImgGrids] = new[] { "output/txt2img-grids" } - }; - public override List LaunchOptions => [ new LaunchOptionDefinition @@ -142,6 +131,8 @@ public class SDWebForge( await using var venvRunner = new PyVenvRunner(venvPath); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs index c35b37b8..037725a8 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionDirectMl.cs @@ -76,6 +76,8 @@ public class StableDiffusionDirectMl( // Setup venv await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); switch (torchVersion) diff --git a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs index 98f85350..5b5cacfa 100644 --- a/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs +++ b/StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs @@ -190,6 +190,8 @@ public class StableDiffusionUx( // Setup venv await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; + await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); switch (torchVersion) diff --git a/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs b/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs index 89d021e0..b1e52339 100644 --- a/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/UnknownPackage.cs @@ -15,8 +15,7 @@ public class UnknownPackage : BasePackage public override string GithubUrl => ""; public override string LicenseType => "AGPL-3.0"; - public override string LicenseUrl => - "https://github.com/LykosAI/StabilityMatrix/blob/main/LICENSE"; + public override string LicenseUrl => "https://github.com/LykosAI/StabilityMatrix/blob/main/LICENSE"; public override string Blurb => "A dank interface for diffusion"; public override string LaunchCommand => "test"; @@ -140,20 +139,20 @@ public class UnknownPackage : BasePackage public override List LaunchOptions => new(); public override Dictionary>? SharedFolders { get; } - public override Dictionary< - SharedOutputType, - IReadOnlyList - >? SharedOutputFolders { get; } + public override Dictionary>? SharedOutputFolders { get; } - public override Task GetLatestVersion( - bool includePrerelease = false - ) + public override Task GetLatestVersion(bool includePrerelease = false) { throw new NotImplementedException(); } public override string MainBranch { get; } + public override Task GetUpdate(InstalledPackage installedPackage) + { + return Task.FromResult(new DownloadPackageVersionOptions { IsLatest = true, VersionTag = "1.8.0" }); + } + public override Task GetAllVersionOptions() => Task.FromResult(new PackageVersionOptions()); diff --git a/StabilityMatrix.Core/Models/Packages/VoltaML.cs b/StabilityMatrix.Core/Models/Packages/VoltaML.cs index 95acb970..dba66a52 100644 --- a/StabilityMatrix.Core/Models/Packages/VoltaML.cs +++ b/StabilityMatrix.Core/Models/Packages/VoltaML.cs @@ -21,12 +21,15 @@ public class VoltaML( public override string DisplayName { get; set; } = "VoltaML"; public override string Author => "VoltaML"; public override string LicenseType => "GPL-3.0"; - public override string LicenseUrl => "https://github.com/VoltaML/voltaML-fast-stable-diffusion/blob/main/License"; + public override string LicenseUrl => + "https://github.com/VoltaML/voltaML-fast-stable-diffusion/blob/main/License"; public override string Blurb => "Fast Stable Diffusion with support for AITemplate"; public override string LaunchCommand => "main.py"; public override Uri PreviewImageUri => - new("https://github.com/LykosAI/StabilityMatrix/assets/13956642/d9a908ed-5665-41a5-a380-98458f4679a8"); + new( + "https://github.com/LykosAI/StabilityMatrix/assets/13956642/d9a908ed-5665-41a5-a380-98458f4679a8" + ); public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Simple; @@ -155,6 +158,7 @@ public class VoltaML( progress?.Report(new ProgressReport(-1, "Setting up venv", isIndeterminate: true)); await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv")); venvRunner.WorkingDirectory = installLocation; + venvRunner.EnvironmentVariables = settingsManager.Settings.EnvironmentVariables; await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false); diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index 01e22fd2..ff65f104 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -118,10 +118,22 @@ public class Settings public Dictionary? UserEnvironmentVariables { get; set; } [JsonIgnore] - public IReadOnlyDictionary EnvironmentVariables => - DefaultEnvironmentVariables - .Concat(UserEnvironmentVariables ?? []) - .ToDictionary(x => x.Key, x => x.Value); + public IReadOnlyDictionary EnvironmentVariables + { + get + { + if (UserEnvironmentVariables is null || UserEnvironmentVariables.Count == 0) + { + return DefaultEnvironmentVariables; + } + + return DefaultEnvironmentVariables + .Concat(UserEnvironmentVariables) + .GroupBy(pair => pair.Key) + // User variables override default variables with the same key + .ToDictionary(grouping => grouping.Key, grouping => grouping.Last().Value); + } + } public HashSet? InstalledModelHashes { get; set; } = new(); diff --git a/StabilityMatrix.Core/Models/SharedFolderType.cs b/StabilityMatrix.Core/Models/SharedFolderType.cs index 50ba7db7..f94b46d8 100644 --- a/StabilityMatrix.Core/Models/SharedFolderType.cs +++ b/StabilityMatrix.Core/Models/SharedFolderType.cs @@ -39,6 +39,7 @@ public enum SharedFolderType InvokeIpAdapters15 = 1 << 24, InvokeIpAdaptersXl = 1 << 25, InvokeClipVision = 1 << 26, + SVD = 1 << 27, PromptExpansion = 1 << 30 } diff --git a/StabilityMatrix.Core/Models/SharedOutputType.cs b/StabilityMatrix.Core/Models/SharedOutputType.cs index d4dede8a..c533de49 100644 --- a/StabilityMatrix.Core/Models/SharedOutputType.cs +++ b/StabilityMatrix.Core/Models/SharedOutputType.cs @@ -8,6 +8,7 @@ public enum SharedOutputType Extras, Text2ImgGrids, Img2ImgGrids, + SVD, Saved, Consolidated }